65.9K
CodeProject 正在变化。 阅读更多。
Home

一套用于创建和操作函子的有用函子

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.20/5 (7投票s)

2003年3月4日

5分钟阅读

viewsIcon

63042

downloadIcon

329

从函数、成员函数和操作函子创建函子。

引言

函子(函数对象)在标准模板库 (STL) 中扮演着重要角色。我创建了几个函子和支持函数来操作函子,以便能够轻松地生成与现有函子略有不同的新函子,而无需重写现有函子。这符合代码重用的原则。

限制

以下函子使用了模板类的偏特化。因此,它不能使用 Visual C++ 编译,因为它不支持偏特化。欢迎任何人将代码移植到 Visual C++。您只需要更改所有函子的名称,使它们变得唯一,例如:FunctionToFunctor1ArgFunctionToFunctor2Arg 等。

转换为函子

要操作函子,您首先需要有函子。然而,遗留库中的许多有用代码不是函子,它们大多是函数,有些可能是成员函数。即使存在函子,它们也可能不符合 STL 标准(即它们没有 typedef 它们的返回类型和参数)。将它们转换为符合 STL 标准的函子并不总是可能的,因为可能无法获得源代码,或者手动转换非常繁琐。

为了方便将这些函数转换为符合 STL 标准的函子,创建了四个具有偏特化的函子。此外,还提供了一个重载的支持函数来简化这四个函子的使用。这些函子是:FunctionToFunctorMemberFunctionToFunctorConstMemberFunctionToFunctorFunctorToFunctor。支持函数是 to_functor。这些函子能够将多达十个参数的函数、成员函数或函子转换为相应的符合 STL 标准的函子。支持的参数数量上限为十个,因为很少有函数的参数超过十个。

用法

FunctionToFunctor 的使用方式是 FunctionToFunctor<Arg1T,Arg2T,....,ArgNT,RetT>,其中 Arg1T..ArgNT (N <=10) 是函数各个参数的类型,RetT 是函数的返回类型。FunctionToFunctor 的构造函数需要函数的名称。

MemberFunctionToFunctor 的使用方式是 MemberFunctionToFunctor <ObjectT,Arg1T,Arg2T,....,ArgN,RetT>,其中 ObjectT 是包含成员函数的对象的类型,Arg1T..ArgNT (N <=10) 是函数各个参数的类型,RetT 是函数的返回类型。MemberFunctionToFunctor 的构造函数需要一个对象实例和成员函数的名称。

ConstMemberFunctionToFunctor 的使用方式是 ConstMemberFunctionToFunctor <ObjectT,Arg1T,Arg2T,....,ArgN,RetT>,其中 ObjectT 是包含成员函数的对象的类型,Arg1T..ArgNT (N <=10) 是函数各个参数的类型,RetT 是函数的返回类型。ConstMemberFunctionToFunctor 的构造函数需要一个对象实例和 const 成员函数的名称。

FunctorToFunctor 的使用方式是 FunctorToFunctor <FunctorT,Arg1T,Arg2T,....,ArgNT,RetT>,其中 FunctorT 是函子的类型,Arg1T..ArgNT (N <=10) 是函数各个参数的类型,RetT 是函数的返回类型。FunctorToFunctor 的构造函数需要一个函子实例。

to_functor 的使用方式是:对于函数,使用 to_functor(function_name);对于成员函数,使用 to_functor(Object_instance, Object::function_name);对于函子,使用 to_functor<Arg1T,Arg2T,...., ArgNT,RetT>(functor_instance)

示例

  int Square(int x) {return x*x;}
  FunctionToFunctor<int,int> square(Square);
  cout << square(3) << endl;  // Output is 9
    
  void Cube(const double& x, double& y) {y = x*x*x;}
  FunctionToFunctor<const double&,double&,void> cube(Cube);
  double z = 0.0;
  cube(2,z);
  cout << z << endl;  // Output is 8
  
  struct Test
  {
      bool IsPositive(double x) {return x > 0;}
      bool IsEven(int x) const {return !(x%2);}
  };
  
  MemberFunctionToFunctor<Test,double,bool> isPos(Test(), Test::IsPositive);
  cout << isPos(3.2) << endl;  // Output is 1
  ConstMemberFunctionToFunctor<Test,int,bool> isEven(Test(), Test::IsEven);
  cout << isEven(4) << endl; // Output is 1
  
  struct IsNegative
  { 
      bool operator()(int x) {return x < 0;}
  };
  
  FunctorToFunctor<IsNegative,int,bool> isNeg(IsNegative());
  cout << isNeg(-2) << endl;  // Output is 1
  
  cout << to_functor(Square)(2) << endl; // Output is 4
  cout << to_functor(Test(), Test::IsPositive)(2.2) << endl; // Output is 1
  cout << to_functor<int,bool>(IsNegative())(4) << endl;  // Output is 0

修改函子的结果

有时能够操作函子的结果是有用的。假设您想创建一个函子,它与现有函子相似,但其结果总是现有函子的 5 倍。为此,我们创建了 AlterFunctorResult

用法

AlterFunctorResult 的使用方式是 AlterFunctorResult<FunctorT,Arg1T,...ArgNT,RetT,BinaryOperationT>,其中 FunctorTArgNT 的定义与上面相同,BinaryOperationT 是一个执行二元运算的函子,它接收两个输入并输出一个单一的输出。例如 STL 中的 plus<>minus<>multiplies<>divides<>AlterFunctorResult 的构造函数需要一个要修改的函子的实例,用于修改现有函子输出的输入,以及一个二元运算函子的实例。

示例

struct Cube  
{ 
  double operator()(double x) {return x*x;}  
}; 
AlterFunctorResult<Cube,double,double,multiplies<double> > 
cubeMultFive(Cube(), 5.0, multiplies<double>());  cout << 
cubeMultFive(3) << endl;  // Output is 135

为函子的参数设置默认值

最后一套函子执行的操作与 STL 库的 bind1stbind2nd 函数相同。也就是说,它允许函子的一个参数具有默认值。因此,在调用函子时,可以省略该参数。STL 库的限制是它只支持最多 2 个参数的函子。这套函子旨在补充 STL 库,支持最多 10 个参数的函子。通过支持最多 10 个参数,这也意味着程序员可以选择绑定从第一个参数到第十个参数,而不仅仅是前两个参数。

用法

这套函子的通用格式是 BindFunctor???,其中 ??? 是 1st、2nd、3rd、4th、5th、6th、7th、8th、9th 或 10th。所有这十套函子都具有相同的语法。例如,要对一个有 4 个参数的函子使用 BindFunctor3rd,您将使用 BindFunctor3rd<FunctorT,Arg1T,Arg2T,Arg3T,Arg4T,RetT>,其构造函数需要函子的实例和第三个参数的默认值。

示例

struct BoxVolume
{
  int operator()(int length, int breadth, int height) 
     {return length * breadth * height;}
};
//Set breadth to be a constant 3
BindFunctor2nd<BoxVolume,int,int,int,int> boxvol(BoxVolume(), 3); 

cout << boxvol(2,5) << endl; // Output is 30
cout << boxvol(1,3) << endl; // Output is 9

摘要

这些函子集的有用性取决于程序员的想象力。我相信它将对泛型编程有用,因为它能够将遗留的 C 函数转换为函子,然后可以将这些函子以多种方式进行操作,然后再馈送到另一个函数。这使得在不重写现有函数的情况下创建新函数成为可能。

请告知我代码中的任何错误,以便我进行纠正。检查代码中的细微编码错误是一件不容易的事,因为代码相当重复且枯燥乏味。我也很乐意了解对代码的任何期望的改进。

© . All rights reserved.