問題を 2 つの部分に分けて構成します。1 つ目は型 (A1、A2 と B1、B2) による区別、2 つ目は変数の初期化による区別です。おっしゃる通り、コードは全て同じですが型がテンプレートじゃないのが思い浮かびます。したがって、私の最初の試みは次のようになります。
template <class X1, class X2>
struct MyStrategy {
void foo()
{
X1 a = /* create appropiate X1 */;
X2 b = /* create appropiate X2 */;
// code that is the same for both except for the types...
}
};
もちろん、関数にはパラメーターや戻り値の型がありますが、要点はわかります。
次に、コメントに残した 2 番目の部分に進みます。値の初期化です。ある種のポリシーベースの設計によってそれを達成します。最初のスケッチ:
template <class X1, class X2>
struct X1X2Creator;
template <>
struct X1X2Creator<A1, A2> {
A1 createX1() { return function1_A(); }
A2 createX2() { return function2_A(); }
};
template <>
struct X1X2Creator<B1, B2> {
B1 createX1() { return function1_B(); }
B2 createX2() { return function2_B(); }
};
template <class X1, class X2>
struct MyStrategy : X1X2Creator<X1, X2> {
void foo()
{
X1 a = this->createX1();
X2 b = this->createX2();
// code that is the same for both except for the types...
}
};
this->createX1()
依存する名前のため、 create-functions を経由して呼び出さなければならないことに注意してください。関数を明示的に修飾することもできます ( X1X2Creator<X1, X2>::createX1()
)。
必要に応じてその設計を改善できます。たとえば、継承を使用せずに X1X2Creator をインスタンス化し、関数を呼び出すか静的にすることです。異なるタイプの組み合わせをさらに使用する場合は、タイプごとに 1 つの作成ポリシーを使用します。
template <class X1, class X2>
struct MyStrategy {
void foo()
{
X1 a = CreationPolicy<X1>::create();
X2 b = CreationPolicy<X2>::create();
// code that is the same for both except for the types...
}
};
同じタイプに異なるポリシーを使用できるようにする場合は、ポリシー クラスをテンプレート パラメーターとして指定します。
template <class X1, class X2,
class X1Creator = CreationPolicy<X1>,
class X2Creator = CreationPolicy<X2>>
struct MyStrategy {
void foo()
{
X1 a = X1Creator::create();
X2 b = X2Creator::create();
// code that is the same for both except for the types...
}
};
HTH