ここには2つの問題があります。1。各子のタイプを決定する方法、および2.複数の子を作成する方法。
作成する子を決定するには
これは、コンパイル時または実行時に実行できます。コンパイル時にこれを行うには、テンプレートが必要です。
template<class Child, class Arg1, class Arg2>
vector<unique_ptr<Parent>> CreateVec(Arg1&& arg1, Arg2&& arg2)
{
vector<unique_ptr<Parent>> result;
result.push_back(unique_ptr<Child>(
new Child(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))));
return result;
}
次のように呼ばれますCreateVec<MyChild>(myArg1, myArg2)
。
実行時に決定する必要がある場合は、実行時変数によってインデックス付けされたファクトリ関数のマップを使用できます。または、ファクトリオブジェクトへのポインタを実行時変数として使用することもできます。
複数の子を作成するには
ここでは、連鎖関数と可変個引数テンプレートのどちらかを選択できます。
連鎖機能
これは本質的にiostreamsが行うことです。ベクトルを作成して1つの子を追加する関数に、2番目の子を追加できるオブジェクトを返し、それ自体を返して続行できるようにします。
ここでの問題は、関数がベクトルを返すようにしたいので、別のオブジェクトを返すこともできないということです。変換演算子を使用してベクトルまたは明示的な関数を取得できますが、おそらく最初にベクトルを作成し、関数を使用して子を追加するのが最も簡単です。
class AddChildren
{
vector<unique_ptr<Parent>>& m_vector;
public:
explicit AddChildren(vector<unique_ptr<Parent>>& theVector)
: m_vector(theVector) {}
template<class Child, class Arg1, class Arg2>
AddChildren& add(Arg1&& arg1, Arg2&& arg2)
{
m_vector.push_back(unique_ptr<Child>(
new Child(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))));
return *this;
}
};
次のように使用されます。
vector<unique_ptr<Parent>> myvector;
AddChildren(myvector)
.add<ChildA>(var1, var2)
.add<ChildB>(var3, var4)
.add<ChildC>(var5, var6);
使用できるタイプを選択する実行時の方法を使用operator()
していて、次のようになっている場合:
vector<unique_ptr<Parent>> myvector;
AddChildren(myvector)
(childAType, var1, var2)(childBType, var3, var4)(childCType, var5, var6);
(これは、子タイプごとに特定のタイプセレクタータイプのダミーオブジェクトをパラメーターとして使用することにより、コンパイル時にタイプを選択することでも実行できます。)
可変個引数テンプレートの使用
可変個引数テンプレートを使用して、一度に3つのパラメーターをはがし、子オブジェクトを追加します。
void addChildren(vector<unique_ptr<Parent>>& theVector)
{}
template<class FirstChild, class FirstArg1, class FirstArg2, class... Rest>
void addChildren(vector<unique_ptr<Parent>>& theVector,
FirstChild childtype, FirstArg1&& arg1, FirstArg2&& arg2, Rest&&... rest)
{
addChild(theVector, childtype,
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2));
addChildren(theVector, std::forward<Rest>(rest)...);
}
template<class... Args>
vector<unique_ptr<Parent>> CreateVec(Args&&... args)
{
vector<unique_ptr<Parent>> result;
addChildren(result, std::forward<Args>(args)...);
return result;
}
ここではaddChild
、型(パラメーターとして)と引数を指定して子を追加できる関数の存在を想定しています。
これに関する主な問題は、VS2012に可変個引数テンプレートがないことです。可変個引数テンプレートをシミュレートする方法は2つあります。1.必要になる可能性のあるパラメーターの最大数を取り、それらのほとんどを「存在しない」という意味で取ることができる既知のタイプにデフォルト設定する単一の関数を記述します。2.必要と思われる数のオーバーロードを書き出します。
子オブジェクトを10個以上必要としないことがわかっている場合、2番目のオプションは実際には完全に実行可能です。1回だけ記述する必要があり、おそらく150行未満のコードです。または、Boost.Preprocessorを使用して関数を生成することもできますが、これはまったく新しいレベルの複雑さです。