可变参数构造函数是否应该隐藏隐式生成的构造函数?
-
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&)
. 。其中重要的部分是它需要一个 const 引用。您的构造函数模板采用非常量引用。
a
不是 const,因此非常量用户声明的构造函数模板优于隐式声明的复制构造函数。要调用隐式声明的复制构造函数,您可以 a
常量:
const Foo a;
Foo b(a);
或者你可以使用 static_cast
获得 const 引用 a
:
Foo a;
Foo b(static_cast<const Foo&>(a));
描述这一点的重载解析规则主要可以在 C++0x FCD 的 §13.3.3.2/3 中找到。第 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&&
, ,并且要么没有其他参数,要么所有其他参数都有默认参数。如果类定义没有显式声明复制构造函数并且没有用户声明的移动构造函数,则复制构造函数将隐式声明为默认值。