次の非常に単純な CRTP 基本クラスがあるとします。
template< class D, class T >
struct Base
{
T foo()
{
return static_cast< D* >(this)->foo_i();
}
};
また、いくつかの派生クラス。すべてがうまく機能しますが、問題があります.2つのクラスにランタイムポリモーフィック動作を持たせたい(コンテナに入れる必要がある)特定の状況が1つ(またはおそらく2つ)あります。言い換えれば、派生 CRTP クラスの一部にも仮想バージョンを持たせたいと考えています。そこで、次のクラスを思いつきました。
template< class T >
struct VirtualBase : public Base< VirtualBase< T >, T >
{
virtual T foo_i() = 0;
};
ここで、ランタイム ポリモーフィズムが必要な場合は、このクラスから派生させます。DerivedB
派生クラスに仮想バージョンを持たせたいとしましょう。バニラ DerivedB は次のようになります。
template< class T >
struct DerivedB : public Base< DerivedB< T >, T >
{
T foo_i()
{
std::cout << "I'm special!\n";
return T();
}
};
私がやりたいことは、基本的にこのクラスに追加のテンプレート パラメーターを追加して、コンパイル時に Base (シミュレートされた「動的」バインディングが必要な場合) または VirtualBase (実際の動的バインディングが必要な場合) から派生するかどうかを選択できるようにすることです。 )。次の疑似 C++ のようなもの:
template< class B, class T >
struct DerivedB : public B< DerivedB< T >, T >
{
T foo_i()
{
std::cout << "I'm special!\n";
return T();
}
};
したがって、プレーンな CRTP の場合はBase
asB
を渡し、仮想クラスの場合はVirtualBase
asを渡しますB
。もちろん、問題は、それらが異なる数の引数を取ることです(Base
派生クラスのタイプが必要です)。私は実用的な解決策を思いつくことができません。
では、コンパイル時に基本クラスを選択するにはどうすればよいでしょうか。または、これがあまりにも複雑/不可能な場合、クラスの静的 (CRTP) バージョンと動的 (仮想) バージョンを作成する最も簡単な方法は何でしょうか?それ以外の場合、実装は同じです。