18
class A
{
};

template <typename A, int S>
class B
{
public:
        static int a[S];

        B()
        {
                a[0] = 0;
        }
};

template<> int B<A, 1>::a[1];

int main()
{
        B<A, 1> t;
        t;
}

GCC 4.1 でコンパイルされますが、リンクされません。

static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a'

配列は型に固有のデータを保持するため、可能であれば初期化を特化したままにしたいと思います。

4

3 に答える 3

40

静的メンバーの特殊化の場合、メンバーを初期化しない場合、特殊化宣言と見なされます。これは、「どこかに特殊化された定義があるため、プライマリ テンプレートからメンバーをインスタンス化しないでください」と言うだけです。定義は .cpp ファイルに表示する必要があり (そうしないと、逆の結果: 複数の定義が得られます)、初期化子を使用しない宣言はヘッダー ファイルに配置する必要があることに注意してください。

現在、正しい構文は実際には次のとおりであり、ヘッダー ファイルではなくファイルに表示されます.cpp

template<> int B<A, 1>::a[1] = { };

以下は、ヘッダー ファイルに引き続き表示されます。

template<> int B<A, 1>::a[1];

これは特殊化宣言として機能します。


このことから、次の構文が必要になるため、既定のコンストラクターのみを持ち、コピーできないメンバーを特殊化することはできません。

// needs a copy constructor!
template<> Type Class<Arguments>::member = Type();

C++0x はこれを修正します:

// doesn't anymore need a copy constructor
template<> Type Class<Arguments>::member{};

私たちの間の標準的な人々のために、ここに引用があります:

14.7.3/6:

テンプレート、メンバー テンプレート、またはクラス テンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、そのような使用が発生するすべての翻訳単位で、暗黙的なインスタンス化を発生させる特殊化の最初の使用の前に宣言する必要があります。 ; 診断は必要ありません。

14.7.3/15:

宣言に初期化子が含まれている場合、テンプレートの静的データ メンバーの明示的な特殊化は定義です。それ以外の場合は宣言です。[注: デフォルトの初期化を必要とするテンプレートの静的データ メンバーを定義するための構文はありません。

template<> X Q<int>::x;

これは、X をデフォルトで初期化できるかどうか (8.5) に関係なく、宣言です。]

3.2/3:

すべてのプログラムには、そのプログラムで使用されるすべての非インライン関数またはオブジェクトの定義が 1 つだけ含まれている必要があります。診断は必要ありません。

3.2/5:

クラス型 (節 9)、列挙型 (7.2)、外部リンケージを持つインライン関数 (7.1.2)、クラス テンプレート (節 14)、非静的関数テンプレート (14.5.5) の複数の定義が存在する可能性があります。 、クラス テンプレートの静的データ メンバー (14.5.1.3)、クラス テンプレートのメンバー関数 (14.5.1.1)、またはプログラムで一部のテンプレート パラメーターが指定されていないテンプレートの特殊化 (14.7、14.5.4) [.. .]

「一部のテンプレートパラメータが指定されていない」というこれの制限は、ヘッダーに配置して、次のことを行うこと許可されていることを意味します (したがって、この特殊化の複数の定義を持つ可能性があります)。

template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;

あなたの場合、すべてのパラメーターが指定されているため、複数の定義を許可するための1つの定義ルールではカバーされません。

于 2010-02-26T15:32:32.150 に答える
2

実際に値を割り当てる必要があります。

template<> int B<A, 1>::a[1] = {0};
于 2010-02-26T15:15:02.677 に答える
1

静的メンバーに値を定義していないため、リンクしません。

template<> int B<A, 1>::a[] = { 0 };

編集:

ところで: 私は常にネイティブ C 型の代わりに boost::array を使用することを好みます:

class A { };

template <typename A, std::size_t S>
class B
{
public:
    static boost::array<int, S> a;

    B() { a[0] = 0; }
};

template<>  boost::array<int, 1> B<A, 1>::a = { };

int main()
{
    B<A, 1> t;
    cout << t.a[0] << endl;
}
于 2010-02-26T15:23:32.047 に答える