Обоснование универсальной эталонной функции шаблона является более жизнеспособным соответствием, чем не шаблонная функция?

Учитывая функцию-член шаблона (... шаблонный конструктор в шаблонном классе, как это происходит), принимающий универсальную переменную ссылку, и другую функцию-кандидат (в моем случае конструктор копирования), и GCC, и Clang выбирают универсальный шаблон ссылки в разрешение перегрузки при копировании объекта. Поскольку два совершенно разных компилятора ведут себя одинаково, я предполагаю, что это действительно "правильная вещь".
Пример кода на https://godbolt.org/g/mip3Fi.

Таким образом, когда копия сделана, есть две жизнеспособные функции-кандидаты с одинаковым количеством параметров, оба с идеальным соответствием (после свертывания ссылок для версии шаблона), из которых одна является кандидатом на специализацию шаблона функции, а другая - нет., И, конечно, из которых призвание одного "явно желательно", тогда как призвание другого - нет.

Мое понимание разрешения перегрузки состоит в том, что среди набора функций-кандидатов должен быть выбран лучший жизнеспособный кандидат, и в случае, если шаблон и не шаблонный кандидат, которые эквивалентно жизнеспособны, конкурируют, выбирается не шаблонный кандидат. Это был бы конструктор копирования.

Очевидно, что компилятор (и, вероятно, стандарт?) Думает иначе. В чем причина этого довольно неочевидного исключения?

Бонусный вопрос:

Как я могу предотвратить это, то есть как сказать компилятору, что я действительно хочу вызывать конструктор копирования при создании копии?

Что-то вроде enable_if_t<!is_same<container<T> const& blahblah...> blah> устраняет плохого кандидата и копирует работу по назначению, но этот подход не слишком полезен, потому что он не скомпилирует момент, когда вы вызываете шаблон с переменным числом аргументов более чем одним аргументом (что является его первоначальной целью!).

Написание initializer_list Функция осведомленности вместо этого будет работать вокруг проблемы, но это превратит идеально перенаправленное emplace в копию и перемещение, что тоже не совсем хорошо.

РЕДАКТИРОВАТЬ:
(вышеуказанный связанный код по запросу)

#include <cstdio>

template<typename T> struct container
{
    container() { puts("default"); }
    container(container const&) { puts("copy"); /* blah */ }
    template<typename... U> container(U&&... args) { puts("template");  /* new T[sizeof...(args)]{std::forward<T>(args)...};  blah blah */ }
};

int main()
{
    container<int> f;
    container<int> g{1,2,3};
    container<int> h(f); // <--- copy constructor most viable form?!
    return 0;
}

0 ответов

Другие вопросы по тегам