9

この質問は、テンプレート クラスの明示的なインスタンス化を検討しています。

B<T>別のテンプレート クラスから派生したテンプレート クラスを考えてみましょうA<T>。そのメソッドは動的リンクから呼び出されるため、明示的にインスタンス化したいB<T>ので、コード自体では呼び出されませんが、メソッドをインスタンス化する必要があります。もちろん、から継承されたメソッドもA<T>呼び出されるため、それらもインスタンス化する必要があります。

この質問で尋ねられるように、テンプレート クラスを明示的にインスタンス化する場合、C++ は基本クラスをインスタンス化しないようです: Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes? 例:

template<typename T>
class A{ void foo(){...} };

template<typename T>
class B : public A<T> {}

template class B<int>; // This will NOT instanciate A<int>::foo()!!!

もちろん、すべての基本クラスをインスタンス化する必要もあります。ただし、クラス階層が非常に深い可能性があるため、これでクライアント コードに負担をかけたくありません。10 個以上のテンプレート クラスを含むクラス階層を考えてみましょう。クライアントは、10 個の明示的なテンプレート インスタンス化を作成するように促されるべきではありません。これはたくさん書いているだけではありません。また、クラス階層に変更を加えると壊れます。

代わりに、インスタンス化されるたびB<T>に、そのすべての基本クラスもインスタンス化されるようにしたいと考えています。次のように、B自体で基本クラスを単純にインスタンス化してみました。

template<typename T>
class B : public A<T> {
    template class A<T>; // Does not compile!
}

しかし、これはコンパイルされません。これを達成できる他の方法はありますか?

4

1 に答える 1

2

洗練されていないかもしれませんが、少なくとも実行可能です: テンプレートをインスタンス化するマクロを提供し、ユーザーが手動でインスタンス化する代わりにマクロを使用する必要があります:

// in A.hpp
#define INSTANTIATE_A(T) template class A<T>;

// in B.hpp
#define INSTANTIATE_B(T) \
    INSTANTIATE_A(T)     \
    template class B<T>;

また、インスタンス化マクロの使用を強制するよりもクラス インターフェイスを "汚染" したい場合protectedは、テンプレートの他のすべてのメンバー関数と基本クラスのバージョンを呼び出すメンバーを追加します。例:

template<typename T>
class A
{
    void foo() {...}
protected:
    void instantiate() { foo(); }
};

template<typename T>
class B : public A<T>
{
    void bar() {...}
protected:
    void instantiate() { A<T>::instantiate(); bar(); }
};

template class B<int>; // Now works as expected

アップデート:

2 番目の解決策の代替: すべてのメンバーの関数ポインターを取得し、それらを一時変数に保存します。

template<typename T>
class A
{
    void foo() {...}
protected:
    void instantiate() { void (A::*p)() = &A::foo; }
};

template<typename T>
class B : public A<T>
{
    void bar() {...}
protected:
    void instantiate() { A<T>::instantiate(); void (B::*p)() = &B::foo; }
};
于 2014-05-20T09:58:01.563 に答える