我试图在这里建立线程:Variable length template arguments list? 要有一个默认的Functor类,这只是学术兴趣。我的目标是构建一个通用的Fucntor类:给定一个类名,方法名和参数类型(可变长度),它构建一个具有operator()方法的类,该方法接受模板args中指定的可变数量类型的参数。获取指针并应用给定的方法。想象一下这样的课程:
class MyClass
{
public:
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
} ;
一个可以在任何函数中使用的模板化仿函数类:
int k = FunctorClass<MyClass, Increment, int, int /*return type*/> (3);
assert(k == 4);
float l = FunctorClass<MyClass, Fraction, float, int, float, /*return type*/> (4,3);
assert(l == (4/3));
可以构建这样的仿函数类吗? 旁注:不能使用Variadic模板,(在VS2010中构建,没有...模板参数) 谢谢你的帮助
答案 0 :(得分:2)
这当然是可行的,例如Boost bind()使用这种方法。但是,如果没有变量,您将无法获得完全的通用性,因为您将被限制为固定数量的模板参数,并且您需要为要支持的每个不同数量的参数键入实现。此外,如果没有左值参考,您将无法获得完美的转发。
那就是说,你试图使用它的方式不会起作用:在说明成员函数时,你不能只是命名它们。您需要使用例如获取正确的成员函数点&MyClass::Increment
和&MyClass::Fraction
。如果成员函数被重载,则需要消除歧义。
由于您显然希望为非静态成员函数启用此函数对象,因此还需要提供一个要在其上调用成员函数的对象。最合理的方法是将对象的引用作为函数对象类的构造函数参数传递,并存储它以便在调用函数时使用。也就是说,使用看起来有些不同,但可以通过某种工厂功能进行简化。这是一个调整各种东西并实现相应的函数对象模板的版本:
#include <cassert>
// -----------------------------------------------------------------------------
template <typename T, T> class FunctorClass;
template <typename RC, typename Class,
RC (Class::*Member)()>
class FunctorClass<RC (Class::*)(), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()() const { return (this->object_->*Member)(); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0,
RC (Class::*Member)(A0)>
class FunctorClass<RC (Class::*)(A0), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0) const { return (this->object_->*Member)(a0); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0, typename A1,
RC (Class::*Member)(A0, A1)>
class FunctorClass<RC (Class::*)(A0, A1), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0, A1 a1) const { return (this->object_->*Member)(a0, a1); }
private:
Class* object_;
};
// -----------------------------------------------------------------------------
class MyClass
{
public:
int foo() { return 17; }
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
};
int main()
{
MyClass object;
int i = FunctorClass<int (MyClass::*)(), &MyClass::foo>(object)();
assert(i == 17);
int k = FunctorClass<int (MyClass::*)(int), &MyClass::Increment>(object)(3);
assert(k == 4);
float l = FunctorClass<float (MyClass::*)(float, int), &MyClass::Fraction>(object)(4,3);
assert(l == (4.0f/3));
}
答案 1 :(得分:0)
我不确定你是否需要variadics来解决这个问题。考虑以下界面......
template < typename RETURN_TYPE >
class iFunctor abstract {
public:
virtual RETURN_TYPE operator () ( void ) = 0;
};
抽象接口不是完整的类,它们可以包含部分实现,例如函数签名和一些数据成员。使用模板,您可以推广返回类型。但是你说的参数列表呢?
注意界面中没有构造函数。在您的具体类(或派生类)中,您可以将变量参数列表的负担传递给构造函数,就像这样......
template < typename TYPE >
class ConcreteFunctor_add : public iFunctor < TYPE > {
private:
int A;
int B;
public:
explicit ConcreteFunctor_add ( const int &a, const int &b ) : A(a), B(b) {};
TYPE operator () ( void ) { return ( A + B ); };
};
您可以通过构造函数逐个处理参数列表。
显式构造函数在声明时需要一个参数列表,因此您将在此处获取变量列表。所以在实践中......
ConcreteFunctor_add < int > addInteger ( 10, 10 );
addInteger();
......你会很酷。