使用Visual C ++ 2010,我有一个这样的类:
class MyClass{
public:
MyClass(){}
MyClass(MyClass &){/*...*/} //A
MyClass(const MyClass &){/*...*/} //B
template<typename T> MyClass(T &&t){ static_assert(
!std::is_same<typename
std::remove_cv<typename std::remove_reference<T>::type>::type,
MyClass>::value,
"Wrapping over wrapping is not allowed!"); } //C
};
int main(int, char**){
MyClass a;
const MyClass b(a); //assert fail if line A removed
auto c=b; //assert fail if line B removed
}
//If both A and B exists
//Warning C4521: multiple copy constructors specified
//Furthermore, if both A and B removed
//No error or warnings; VC2010 accepts peacefully.
//In debug mode you will find the compiler generated trivial copy constructor
根据C ++标准,A行和B行都被认为是复制构造函数,C是转换构造函数。我收到警告,我宣布多个拷贝构造函数,这并不奇怪。但是,如果我删除它们中的任何一个,static_assert失败并且代码将无法编译,这意味着模板构造函数接收到控件。
我确信此行为遵循函数重载规则。然而,这是两个规则的冲突吗?如果A和B是复制构造函数并且其中一个被声明,那么复制对象的任何尝试都不应该放到模板中,是不是?
更新: 根据N3242,12.8.7,
“成员函数模板永远不会安装,以便将类对象的副本执行到其类类型的对象。”
正确的实施应该是:
有任何评论吗?
答案 0 :(得分:1)
首先,template<T>
应为template <typename T>
。
我在64位Ubuntu Linux上使用gcc 4.4.3,代码的行为与你在帖子中演示的不同。
const MyClass b(a);
中失败。原因是对象a不是常量,因此构造函数B不能匹配,编译器必须实例化模板构造函数。当然,const MyClass
和MyClass
是不同的类型。is_same<MyClass&&, MyClass>::value
是真的。您可以使用typeid打印出两种类型。答案 1 :(得分:0)
如果A和B是复制构造函数并且其中一个被声明,那么任何复制对象的尝试都不应该放到模板中,是不是?
不是复制构造函数的构造函数仍可用于复制对象。在您的情况下,从构造函数模板实例化的构造函数用于复制对象。哪个没问题。