Должны ли вариальные конструкторы скрывать неявно сгенерированные?
-
22-10-2019 - |
Вопрос
Должен ли варидические конструкторы скрывать неявно сгенерированные, то есть конструктор по умолчанию и конструктор копирования?
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&&
, и либо нет других параметров, либо все другие параметры имеют аргументы по умолчанию.Если определение класса явно не объявляет конструктор копии, и нет никакого пользовательского конструктора перемещения, конструктор копирования неявно объявляется как дефолт.