2

C++98 標準は次のように述べています。

[temp.class.spec] 部分的な特殊化宣言自体は、名前検索では見つかりません。

これが明示的な特殊化にも当てはまる場合、クラス テンプレートの明示的/部分的な特殊化の前方宣言が非表示になります。

[temp.class.spec.match] クラスのインスタンス化が必要なコンテキストでクラス テンプレートが使用される場合、インスタンス化がプライマリ テンプレートを使用して生成されるか、部分的な特殊化の 1 つを使用して生成されるかを決定する必要があります。

これは、明示的/部分的な特殊化の選択が、一致する特殊化の (暗黙の) インスタンス化の時点まで行われないことを意味します。これは、クラスを完全に定義する必要がある場合にのみ発生します。

次の例では、前方宣言された明示的な特殊化が持つ唯一の効果は、プログラムのコンパイルを失敗させることです。

namespace N
{
    template<class T>
    struct S
    {
    };

    typedef S<char> Type; // name lookup finds S<T>

    template<>
    struct S<char>; // invisible to name lookup

    typedef S<char> Type; // name lookup finds S<T>

    int f(S<char>*); // name lookup finds S<T>

    S<int> object; // implicitly instantiates S<int>

    template<>
    struct S<int>; // illegal, explicit specialization after instantiation
}

N::S<char>* p = 0; // name lookup finds N::S<T>
int i = f(p); // name lookup finds N::f via ADL


N::S<char> object; // illegal, incomplete type N::S<char>

どちらの場合も、(特殊化を削除する以外に) プログラムをコンパイルする唯一の方法は、インスタンス化する前に両方の特殊化の定義を提供することです。これにより、前方宣言が少し無意味になります。

この動作には、実用的な実際のアプリケーションがありますか? これとは別に、これらの前方宣言が役立つものはありますか?

4

1 に答える 1

4

プログラムをコンパイルに失敗させることが唯一の目的であるというのは真実ではありません。以下でV2は、V1 は整形式ですが、「整形式ではありません。診断は必要ありません」です。

namespace N {
   template<typename T> struct A {
      friend void f(A *a) { } // would take this with V2
   };
}
void f(void*) { } // would take this with V1

namespace N {
/* V1: */ template<> struct A<int>;
}

int main() {
   N::A<int> *p;
   f(p);
}

namespace N {
/* V2: */ template<> struct A<int>;
}
于 2013-06-19T21:21:02.943 に答える