我正在尝试定义一个像任务农场一样的递归构造。在这里,我正在尝试两个操作数,这些操作数可以递归地用于任何数量的操作数,因为它可以嵌套自己。
template <typename T1, typename T2>
class Farm
{
private:
T1 *task1;
T2 *task2;
public:
// save them so that I can use them when invoking call operator
Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { }
void operator()()
{
// invoke call operator, meaning a farm could be a task (arbitrary nesting)
(*task1)();
(*task2)();
}
};
int main()
{
... create two pointer(A *a, B *b...)
Farm(a,b); // error: missing template arguments before ‘(’ token
Farm<A, B>(a,b); // in this works, it works
}
问题在于自动检测模板参数,在这种情况下不起作用。我做错了什么,我怎么能通过gcc编译器实现这个模板参数隐式检测。
谢谢!
答案 0 :(得分:16)
类/构造函数不像函数那样自动检测类型。您需要编写一个包装函数来创建您的类。
这样做如下并称为Object Generator模式。 (谢谢@Itjax!)
template <typename T1, typename T2>
Farm<T1, T2> makeFarm(T1* a, T2* b) {
return Farm<T1,T2>(a,b);
}
// silly example
Farm<T1,T2> farm = makeFarm(a,b);
// better example
template<typename T>
void plow(T& farm) { farm.applyTractor(...); }
void blah() {
plow(makeFarm(b,a))
}
当你想使用一些参数创建模板化类的临时对象并避免指定它们的类型时,这种模式在使用lambda / bind / foreach和类似的部分时会出现很多,通常会将它发送到另一个模板函数中({ {1}})或多态对象(std::for_each
)。
注意:生成器函数通常是内联的,并且通过copy-elision优化,可能根本没有在代码中调用的复制构造函数。如果你不能复制你的对象,makeFarm()应该返回一个智能指针(在现代C ++中首选std::function
)。
答案 1 :(得分:4)
通常的解决方法是提供一个返回实际实现的模板函数。标准C ++库使用了这个,例如,与std :: make_pair。
示例:
template<typename T>
struct foo_t {
...
};
template<typename T>
foo_t<T> foo(T const &f) {
return foo_t<T>(f);
}
这是有效的,因为对于函数,允许编译器从参数列表中推断出类型名。
答案 2 :(得分:1)
您可以为类Farm添加基类:
class FarmBase
{
public:
virtual ~FarmBase(){}
virtual void operator()() = 0;
};
template <typename T1, typename T2>
class Farm : public FramBase
{
private:
T1 *task1;
T2 *task2;
public:
// save them so that I can use them when invoking call operator
Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { }
virtual ~Farm(){}
virtual void operator()()
{
// invoke call operator, meaning a farm could be a task (arbitrary nesting)
(*task1)();
(*task2)();
}
};
template< typename A, typename B >
FarmBase* Create( A *a, B *b )
{
return new Farm< A, B >( a, b );
}
然后主要看起来像:
int main()
{
//... create two pointer(A *a, B *b...)
FarmBase *fobj = CreateFarm( a, b );
}