问题描述
|
我试图定义一个像任务耕作这样的递归构造。在这里,我正在尝试两个可以嵌套的操作数,这些操作数可以递归地用于任何数量的操作数。
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编译器实现此模板参数隐式检测。
谢谢!
解决方法
类/构造函数不会像函数那样自动检测类型。您需要编写包装函数来创建您的类。
如下所述,并称为对象生成器模式。 (感谢@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和类似的部件时,当您想创建带有某些参数的模板类的临时对象并避免指定其类型时,这种模式会出现很多,通常将其发送到另一个模板函数(std::for_each
)或多态对象(std::function
)。
注意:生成器函数通常是内联的,并且通过复制删除优化,您的代码中可能根本不会调用任何复制构造函数。如果无法复制对象,则makeFarm()应该返回一个智能指针(在现代C ++中,preferred4ѭ是首选)。
, 通常的解决方法是提供一个返回实际实现的模板函数。标准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);
}
之所以可行,是因为对于函数,编译器可以从参数列表中推断出类型名称。
, 您可以为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 );
}