C++ явный универсальный ссылочный конструктор не скрывает конструктор копирования?
Наверное, мое понимание explicit
недостаточно, но я удивляюсь, почему в следующем коде конструктор копирования не скрывается неверсальным ссылочным конструктором, когда я объявляю последний как explicit
,
struct A
{
A() = default;
template<typename T>
A(T&& t) { std::cout<<"hides copy constructor"<<std::endl; }
};
struct A_explicit
{
A_explicit() = default;
template<typename T>
explicit A_explicit(T&& t) { std::cout<<"does not hide copy constructor?"<<std::endl; }
};
int main()
{
A a;
auto b = a; (void) b; //prints "hides copy constructor"
A_explicit a_exp;
auto b_exp = a_exp; (void) b_exp; //prints nothing
}
Это общее решение вместо материала SFINAE, которое можно было бы применить иначе, чтобы предотвратить скрытие A
(например, std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>
смотрите здесь)
2 ответа
Конструктор отмечен как explicit
не участвует в разрешении перегрузки во время инициализации копирования (A a = b;
кроме всего прочего).
Он участвует в инициализации copy-list (A a = {b1};
) и вызывает некорректную работу программы, если она выбрана.
... кроме случаев, когда вещь в фигурных скобках A
или класс, полученный из него, и в этом случае недавний отчет о дефектах изменил правила, чтобы сказать, что в этой конкретной ситуации вместо этого выполняется инициализация копирования - и так explicit
конструкторы опять просто полностью игнорируются.
Я знаю, очень обучаем.
Это общее решение вместо материала SFINAE, которое можно было бы применить иначе, чтобы предотвратить сокрытие в A?
Нет. Потому что этот конструктор все равно выиграет разрешение перегрузки для прямой инициализации:
A_explicit a, b(a); // will call the constructor taking a forwarding reference
В A
конструктор копирования не скрыт. Компилятор неявно объявляет это, как всегда. Это просто теряет разрешение перегрузки, потому что его тип параметра (const A&
) имеет дополнительную cv-квалификацию по сравнению с параметром специализации шаблона конструктора (A&
). Если бы вы сделали
auto b = static_cast<const A&>(a);
вы бы увидели, что будет вызван конструктор копирования.
В A_explicit
шаблон не представляется кандидатом на разрешение перегрузки вообще, потому что он объявлен explicit
, Неявно объявленный конструктор копирования все еще там, как и в A
так оно и называется.