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が失敗し、コードがコンパイルされません。つまり、テンプレートコンストラクターが制御を受け取りました。
この振る舞いは関数のオーバーロードのルールに従っていると確信しています。しかし、これは2つのルールの矛盾ですか?AとBがコピーコンストラクターであり、そのうちの1つが宣言されている場合、オブジェクトをコピーしようとしても、テンプレートにドロップしないでください。
更新:N3242、12.8.7によると、
「メンバー関数テンプレートは、クラスオブジェクトのそのクラスタイプのオブジェクトへのコピーを実行するためにインスタンス化されることはありません。」
正しい実装は次のとおりです。
- AまたはB、あるいはその両方を削除しても、アサートエラーは発生しません。
- ラインBが削除された場合、bは定数であるため、cの構築は失敗するはずです。
- 両方の行が削除された場合、コンパイラはクラスのコピーコンストラクタを生成する必要があります。
- 両方の行が存在する場合にユーザーに警告するのは実装次第です。
任意のコメント?