【发布时间】:2011-12-14 14:35:28
【问题描述】:
使用 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,
“从不实例化成员函数模板来执行将类对象复制到其类类型的对象。”
正确的实现应该是:
- 当 A 或 B 或两者都被移除时,不会发生断言失败。
- 如果删除行 B,c 的构造应该会失败,因为 b 是 const。
- 如果删除了这两行,编译器应该为该类生成一个复制构造函数。
- 如果两条线都存在,则由实现来警告用户。
有什么意见吗?
【问题讨论】:
-
你自己带来了这个,包括
static_assert。我想不出任何理由不允许从类型T&转换为类型const T&- 你可以吗? -
这只是我的类的一个虚拟实现。模板构造函数的逻辑应该与复制构造函数不同。
-
为了实现模板转换构造函数,通常应该使用一个包含的存储来存储t的值。如果 t 是 MyClass 的实例,它将引入 wrapping over wrapping,这是我要防止的。
-
我明白你为什么现在问。原始代码具有误导性。我已经更新了代码。
标签: templates visual-c++ constructor c++11 gcc4