这里有两个问题,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 所做的。让创建向量并添加单个子项的函数返回一个对象,该对象允许您添加第二个子项,并返回自身允许您继续。
这里的问题是你希望函数返回向量,所以它不能也返回另一个对象。您可以使用转换运算符来获取向量或显式函数,但可能最简单的方法是首先创建向量,然后使用函数添加子项。
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);
(这也可以通过使用每个子类型的特定类型选择器类型的虚拟对象作为参数来在编译时选择类型来完成。)
使用可变参数模板
使用可变参数模板一次剥离三个参数,并添加一个子对象。
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 没有可变参数模板。有两种方法可以模拟可变参数模板。1. 编写一个函数,该函数采用您可能需要的最大参数数量,并将它们中的大多数默认为某种已知类型,您可以将其视为“不存在”。2. 写出你认为需要的尽可能多的重载。
如果你知道你永远不需要超过十个子对象,那么第二个选项实际上是完全可行的——你只需要编写一次它们,它可能少于 150 行代码。或者,您可以使用 Boost.Preprocessor 生成函数,但这是一个全新的复杂程度。