Должны ли вариальные конструкторы скрывать неявно сгенерированные?

StackOverflow https://stackoverflow.com/questions/2953611

Вопрос

Должен ли варидические конструкторы скрывать неявно сгенерированные, то есть конструктор по умолчанию и конструктор копирования?

struct Foo
{
    template<typename... Args> Foo(Args&&... x)
    {
        std::cout << "inside the variadic constructor\n";
    }
};

int main()
{
    Foo a;
    Foo b(a);
}

Каким -то образом я ожидал, что это ничего не печатает после прочтения этот ответ, но печатает inside the variadic constructor дважды на G ++ 4.5.0 :( Правильно ли это поведение?


Это также происходит без вариальных шаблонов:

struct Foo
{
    Foo()
    {
        std::cout << "inside the nullary constructor\n";
    }

    template<typename A> Foo(A&& x)
    {
        std::cout << "inside the unary constructor\n";
    }
};

int main()
{
    Foo a;
    Foo b(a);
}

Опять же, обе линии напечатаны.

Это было полезно?

Решение

Объявление о неявном заявленном конструкторе копирования, на самом деле, не является подавленным. Это просто не называется из -за правил разрешения перегрузки.

Неявно объявленный конструктор копии имеет форму Foo(const Foo&). Анкет Важной частью этого является то, что это требует константной ссылки. Ваш шаблон конструктора берет на себя неконтролируемую ссылку.

a не является const, поэтому неконтролируемый пользовательский шаблон конструктора предпочтительнее, чем неявно декоративный конструктор копирования. Чтобы вызвать неявно декоративный конструктор копирования, вы можете сделать a Конст:

const Foo a;
Foo b(a);

или вы можете использовать static_cast Для получения константной ссылки на a:

Foo a;
Foo b(static_cast<const Foo&>(a));

Правила разрешения перегрузки, которые описывают это, находятся в основном в §13.3.3.2/3 C ++ 0x FCD. Этот конкретный сценарий с комбинацией ссылок LVALUE и RVALUE описывается различными примерами на стр. 303.


Шаблон варидового конструктора подавит неявно объявленный конструктор по умолчанию, поскольку шаблон варидового конструктора будет декорирован пользователем, а конструктор по умолчанию неявно объявляется только в том случае, если нет конструкторов, предопределенных пользователем (C ++ 0x FCD §12.1/5):

Если нет конструктора, разработанного пользователем для класса X, конструктор, не имеющий параметров, неявно объявляется как дефолт.

Шаблон варидового конструктора не будет подавлять неявно объявленный конструктор копирования, потому что только конструктор, не отображаемый, может быть конструктором копирования (C ++ 0x FCD §12.8/2, 3 и 8):

Неэлементный конструктор для класса X является конструктором копирования, если его первый параметр имеет тип X&, const X&, volatile X& или же const volatile X&, и либо нет других параметров, либо все другие параметры имеют аргументы по умолчанию.

Неэлементный конструктор для класса X является конструктором движения, если его первый параметр имеет тип X&&, const X&&, volatile X&&, или же const volatile X&&, и либо нет других параметров, либо все другие параметры имеют аргументы по умолчанию.

Если определение класса явно не объявляет конструктор копии, и нет никакого пользовательского конструктора перемещения, конструктор копирования неявно объявляется как дефолт.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top