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
}

DEMO

Это общее решение вместо материала 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так оно и называется.

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