Должны ли вариадические конструкторы скрывать неявно генерируемые? - PullRequest
27 голосов
/ 02 июня 2010

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

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);
}

Опять обе строки напечатаны.

1 Ответ

21 голосов
/ 02 июня 2010

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

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

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

const Foo a;
Foo b(a);

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

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

Правила разрешения перегрузки, описывающие это, находятся в основном в §13.3.3.2 / 3 FCD C ++ 0x. Этот конкретный сценарий с комбинацией ссылок 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&&, а других параметров либо нет, либо все остальные параметры имеют аргументы по умолчанию.

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

...