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

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

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 ответ

Решение

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

Неявно объявленный конструктор копирования имеет вид 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.


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

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

Шаблон конструктора variadic не будет подавлять неявно объявленный конструктор копирования, поскольку только конструктор не шаблонов может быть конструктором копирования (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&&и либо нет других параметров, либо все остальные параметры имеют аргументы по умолчанию.

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

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