Foo<T>
私は派生したテンプレート クラスを持っていますFooDerived<T>
。これは、テンプレート クラスのテンプレート引数です。Bar<T>
つまり、最終的には のようなものになりBar< FooDerived<T> >
ます。
template <typename T>
class Foo
{
public:
typedef T type_t;
virtual double compute() { return 1.0; }
};
template <typename T>
class FooDerived : public Foo<T>
{
public:
double compute() { return 42.0; }
};
template <typename T>
class Bar : public T
{
public:
void f()
{
// This function could vary depending on U (and possibly T)
std::cout << "Bar< T<U> > : " << this->compute() << std::endl;
}
};
Bar
のテンプレート引数に基づいて特殊化しようとしていますFooDerived
。たとえば、Bar< FooDerived<int> >
andBar< FooDerived<float> >
は異なる動作をします。
int main(void)
{
Bar< FooDerived<int> > a;
a.f();
Bar< FooDerived<float> > b;
b.f();
}
C++03 (または C++11) でこれを効率的に達成するにはどうすればよいですか? 効率的とは、無駄なコードの重複を避けたいという意味です(実際のプログラムには、この例よりも多くの型と関数が含まれます)。また、コードを使用する人は、コードを変更する必要なく専門化を追加できる必要があるため、どのような種類のswitch
ソリューションも適応されません。
boost::mpl
タイプをチェックするなど、boost::mpl::if_
を含む SFINAE のようなソリューションを見てきましたがboost::is_same
、私の目的を達成するものは何もないようでした。これは、その種のテンプレートの特殊化には適合しない可能性があると思います。error: redefinition of 'Bar'
たとえば、次のようなことをしようとすると、コンパイラはそれを特殊化として認識していないように見えるため、常に終了します。
テンプレート クラス バー : public T、private boost::mpl::if_、int、boost::mpl::false_>
boost::mpl::if_
をプライベート継承または追加のテンプレート引数として使用しても、特殊化は可能ではないようです。
では、このようなことを達成するための適切な方法は何ですか?
更新 1
すべてのケースを特殊化することは可能ですが、この例の背後に隠れている実際の問題は、実際にはもっと複雑です。ストレージタイプ(密または疎行列)である(関数、微分可能な関数、2回微分可能な関数など)から派生するCachedFunction<T> : public T
場所があります。実装がストレージタイプと関数のタイプに依存する多数の関数が含まれています。したがって、メタプログラミングは、コードの重複を回避するための良い方法のように思えました。T
Function<U>
U
CachedFunction
更新 2
提供された回答に応じて:関連するすべてのケースで、これらの明示的なテンプレートの特殊化を回避しようとしています。から派生した 3 つまたは 4 つのクラスFoo
があり、 には 2 つまたは 3 つの型があり、 の型と考慮される派生クラスに基づいて異なる処理が必要な 6 つまたは 7 つの関数が含まれFoo
ていると想像してみてください。基本的に、 、およびごとに、次を実装する必要があります。Bar
Foo
i
j
k
template<> void Bar<FooDerived_i<Type_j> >::f_k(){ ... }
したがって、他の「よりクリーンな」方法があるかどうかを確認しようとしています。
更新 3
を使用するboost::is_same
と、このようなことができますが、この解決策では、コードを変更せずに新しい型を処理することが難しくなります。
例を次に示します。
#include <iostream>
#include <boost/type_traits/is_same.hpp>
typedef int type1;
typedef float type2;
template <typename T>
class Foo
{
public:
typedef T type_t;
virtual double compute() { return 1.0; }
};
template <typename T>
class FooDerived
{
public:
typedef T type_t;
double compute() { return 42.0; }
};
template <class T>
class Bar : public T
{
public:
void f()
{
// types have to be known...
if (boost::is_same<typename T::type_t, type1>::value)
std::cout << "Bar< T<type1> > : " << this->compute() << std::endl;
else if (boost::is_same<typename T::type_t, type2>::value)
std::cout << "Bar< T<type2> > : " << this->compute() << std::endl;
}
};
int main(void)
{
Bar< Foo<type1> > a;
a.f();
Bar< FooDerived<type2> > b;
b.f();
}