使用某些代码更容易解释,所以我先给出一个例子:
#include <iostream>
#include <vector>
class Base {
public:
int integer;
Base() : integer(0) {}
Base(int i) : integer(i) {}
};
class Double: public Base {
public:
Double(int i) { integer = i * 2; }
};
class Triple: public Base {
public:
Triple(int i) { integer = i * 3; }
};
template<typename T>
Base* createBaseObject(int i) {
return new T(i);
};
int main() {
std::vector<Base*> objects;
objects.push_back(createBaseObject<Double>(2));
objects.push_back(createBaseObject<Triple>(2));
for(int i = 0; i < objects.size(); ++i) {
std::cout << objects[i]->integer << std::endl;
}
std::cin.get();
return 0;
}
我正在尝试创建一个函数,该函数将返回一个Base
指针,该指针指向一个派生自Base
的对象。在上面的代码中,函数createBaseObject
允许我这样做,但它限制了我,因为它只能创建将一个参数带入其构造函数的衍生类。
例如,如果我想创建一个派生类Multiply:
class Multiply: public Base {
public:
Multiply(int i, int amount) { integer = i * amount; }
};
createBaseObject
将无法创建Multiply
对象,因为它的构造函数需要两个参数。
我想最终做这样的事情:
struct BaseCreator {
typedef Base* (*funcPtr)(int);
BaseCreator(std::string name, funcPtr f) : identifier(name), func(f) {}
std::string identifier;
funcPtr func;
};
然后,例如,当我得到匹配identifier
的输入时,我可以创建一个新对象,该任何派生类与该标识符关联,并输入任何参数,并将其推送到容器。
在阅读了一些回复之后,我认为这样的事情符合我的需要,能够在程序上创建一个对象的实例?我对模板并不太明智,所以我不知道这是否合法。
struct CreatorBase {
std::string identifier;
CreatorBase(std::string name) : identifier(name) {}
template<typename... Args>
virtual Base* createObject(Args... as) = 0;
};
template<typename T>
struct Creator: public CreatorBase {
typedef T type;
template<typename... Args>
Base* createObject(Args... as) {
return new type(as...);
}
};
好的,这是迄今为止我设法提出的另一个半解决方案:
#include <boost\lambda\bind.hpp>
#include <boost\lambda\construct.hpp>
#include <boost\function.hpp>
using namespace boost::lambda;
boost::function<Base(int)> dbl = bind(constructor<Double>(), _1);
boost::function<Base(int, int)> mult = bind(constructor<Multiply>(), _1, _2);
这与原版有相同的限制,因为我没有一个指向dbl
和mult
的指针。
答案 0 :(得分:5)
C ++ 11 variadic templates可以为你做到这一点。
您已经拥有了新的派生类:
class Multiply: public Base {
public:
Multiply(int i, int amount) { integer = i * amount; }
};
然后改变你的工厂:
template<typename T, typename... Args>
Base* createBaseObject(Args... as) {
return new T(as...);
};
最后,允许推断出论点:
objects.push_back(createBaseObject<Multiply>(3,4));
正如其他人所说,但这一切似乎都毫无意义。大概你的真实用例不那么做作。
答案 1 :(得分:3)
为什么不提供带有模板化参数的多次重载?
template<typename TBase, TArg>
Base* createBaseObject(TArg p1) {
return new TBase(p1);
};
template<typename TBase, TArg1, TArg2>
Base* createBaseObject(TArg p1, TArg2 p2) {
return new TBase(p1, p2);
};
答案 2 :(得分:1)
使用可变参数模板:
template <typename R, typename ...Args>
Base * createInstance(Args &&... args)
{
return new R(std::forward<Args>(args)...);
}
用法:objects.push_back(createInstance<Gizmo>(1, true, 'a'));
有点难以理解为什么你会想要这个,不过,你可能只是说:
objects.push_back(new Gizmo(1, true, 'a'));
更好的方法是声明向量带有std::unique_ptr<Base>
个元素。