4

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の構築は失敗するはずです。
  • 両方の行が削除された場合、コンパイラはクラスのコピーコンストラクタを生成する必要があります。
  • 両方の行が存在する場合にユーザーに警告するのは実装次第です。

任意のコメント?

4

2 に答える 2

1

まず第一に、template<T>する必要がありますtemplate <typename T>

私は 64 ビットの Ubuntu Linux で gcc 4.4.3 を使用しています。コードの動作は、投稿で示したものとは異なります。

  • 何も変更されていない場合、コードは警告なしでコンパイルできます。コンストラクター A と B が次々と呼び出されます。
  • 行 A にコメントすると、あなたが言ったようにコンパイルに失敗します: 行で失敗しますconst MyClass b(a);。その理由は、オブジェクト a が定数ではないため、コンストラクター B を一致させることができず、コンパイラーはテンプレート コンストラクターをインスタンス化する必要があるためです。もちろん、const MyClassMyClassはタイプが異なります。
  • ただし、行 B のみをコメントすると、コードは正常にコンパイルされ、テンプレート コピー コンストラクターが呼び出されました。オブジェクト b は定数オブジェクトであるため、コンストラクト A を一致させることができず、コンパイラはテンプレート コンストラクターをインスタンス化します。しかし、疑問が残ります: static_assert が失敗するべきかどうか? 違いは、プラットフォーム/コンパイラの違いが原因である可能性があります。GCC は true を実装しis_same<MyClass&&, MyClass>::valueているようです。typeid を使用して、両方のタイプを出力できます。
于 2011-10-25T06:55:40.513 に答える
0

A と B がコピー コンストラクターで、そのうちの 1 つが宣言されている場合、オブジェクトをコピーしようとしても、テンプレートにドロップされるべきではありませんか?

コピー コンストラクターではないコンストラクターを使用して、オブジェクトをコピーできます。あなたの場合、コンストラクターテンプレートからインスタンス化されたコンストラクターは、オブジェクトのコピーに使用されます。それは結構です。

于 2011-10-25T11:00:38.860 に答える