9

テンプレートクラスの特別なメンバー関数(具体的には、コピー/ムーブコンストラクターとコピー/ムーブ代入演算子)はいつインスタンス化されますか?クラス自体がインスタンス化されるとすぐに、または必要なときにのみですか?

これは、次の状況で発生します。

template <class T, class U>
struct pair
{
    T first;                 
    U second;                

    pair() : first(), second() {}

    pair(const pair&) = default;
};

struct S
{
    S() {}
    S(const S&) = delete;
    S(S&&) = default;
};

int main()
{
    pair<int, S> p;
}

Clangはこのコードのコンパイルを拒否し、次のエラーが発生します。

test.cpp:9:5: error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be
      non-const
    pair(const pair&) = default;
    ^
test.cpp:21:18: note: in instantiation of template class 'pair<int, S>' requested here
    pair<int, S> p;
                 ^

クラスがインスタンス化されるとすぐにコピーコンストラクターをインスタンス化しようとすることを示唆しています。

ただし、GCCはコードを正常にコンパイルするため、実際に必要な場合にのみコピーコンストラクターをインスタンス化しようとすることを示唆しています。

どのコンパイラの動作が正しいですか?

(代入演算子についても同様の不一致が見られます。)

更新pair:これは、この例のコピーコンストラクターがedであるという事実と関係があります。これは、defaultその定義を次のように変更した場合です。

pair(const pair& p) : first(p.first), second(p.second) {}

次に、コードはclangも渡します。

4

2 に答える 2

5

現在のC++11標準のセクション14.7.1をご覧ください。ドラフトのn3242バージョンから引用するには:

クラステンプレート特殊化の暗黙的なインスタンス化により、クラスメンバー関数、メンバークラス、静的データメンバー、およびメンバーテンプレートの宣言の暗黙的なインスタンス化が発生しますが、定義やデフォルトの引数のインスタンス化は発生しません。そしてそれはメンバーの匿名組合の定義の暗黙のインスタンス化を引き起こします。クラステンプレートのメンバーまたはメンバーテンプレートが明示的にインスタンス化されているか、明示的に特殊化されていない限り、メンバー定義が存在する必要があるコンテキストで特殊化が参照される場合、メンバーの特殊化は暗黙的にインスタンス化されます。特に、

つまり、上記のようにクラスを型として使用すると、宣言のみがインスタンス化されます。したがって、コピーコンストラクターの実際の(デフォルトの)実装は、上記のコードでは必要ないため、インスタンス化しないでください。したがって、GCCはこれを正しく処理していますが、Clangは処理していません。

また、編集では、直接実装されたコピーコンストラクターにも障害があるため、Clangがデフォルトのコピーコンストラクターの実装を生成するのが早すぎることを示唆していSます(独自の実装で行っているように、のコピーコンストラクターを呼び出すことはできません)。デフォルトの実装と実装はすべての点(インスタンス化の時間を含む)で同じである必要があるため、これはclangのバグと見なします。

于 2012-04-29T09:08:44.213 に答える
3

標準の関連する一節は[dcl.fct.def.default]/1です。

明示的にデフォルト設定されている関数は、宣言された関数型が同じである必要があります(ref-qualifierが異なる可能性があり、コピーコンストラクターまたはコピー代入演算子の場合を除いて、パラメーター型は「 -const T"、ここTで、はメンバー関数のクラスの名前です)暗黙的に宣言されたかのように)

このルールは、デフォルトの関数が使用されない場合でも適用されます。さて、[class.copy] /9はこう言っています:

暗黙的に宣言されたコピーコンストラクタは、次の形式になります。

X::X(const X&)

そのすべての非静的データメンバーがXクラスタイプM[...]である場合、そのような各クラスタイプには、最初のパラメーターがタイプconst M&または。であるコピーコンストラクターがありますconst volatile M&

それ以外の場合、暗黙的に宣言されたコピーコンストラクタは次の形式になります

X::X(X&)

したがって、このような例は形式が正しくありません(そして、表示されている診断を生成する必要があります)。

struct A {
  A();
  A(A&); // Note, non-const type A in copy constructor
};
template<typename T>
struct B {
  T t;
  B();
  B(const B&) = default;
};
B<A> b; // error, B<A>::B(const B&) is defaulted but has the wrong type

ただし、この例では、このルールは適用されません。clangのバグ(すでに修正されています)が原因で、削除されたコピーコンストラクターは非constパラメーター型であると誤って見なされ、このエラーが発生しました。

于 2012-04-29T21:45:54.317 に答える