我使用 C++ 模板传入策略函子来更改函数的行为。效果很好。我传递的函子是一个无状态类,没有存储,它只是以经典函子方式重载 () 运算符。

template <typename Operation> int foo(int a) 
{
int b=Operation()(a);
/* use b here, etc */
}

我经常这样做,而且效果很好,而且我经常使用传入的 6 或 7 个模板化函子来制作模板!

然而,我既担心代码的优雅性,又担心效率。函子是无状态的,所以我假设 Operation() 构造函数是免费的,并且函子的求值与内联函数一样高效,但像所有 C++ 程序员一样,我总是有一些挥之不去的疑问。

我的第二个问题是我是否可以使用替代函子方法。它不会覆盖 () 运算符,但会在构造函数中执行所有操作作为副作用!就像是:

struct Operation {
  Operation(int a, int &b) { b=a*a; }
};
template <typename Operation> int foo(int a) 
 {
   int b;
   Operation(a,b);
    /* use b here, etc */
 }

我从未见过有人使用构造函数作为仿函数的“工作”,但看起来它应该可以工作。有什么优势吗?有什么缺点吗?我确实喜欢删除奇怪的双括号 "Operator()(a)" ,但这可能只是为了美观。

有帮助吗?

解决方案

有什么缺点吗?

  • Ctor 不返回任何有用的值——不能在链式调用中使用(例如foo(酒吧())。
  • 他们可以扔。
  • 设计观点——ctors 是对象创建函数,并不是真正的主力。

其他提示

  1. 编译器实际内联操作的空构造函数(在类似情况下至少是gcc,除非你关闭了优化)
  2. 在构造函数中执行所有操作的缺点是您不能以这种方式创建具有某种内部状态的仿函数 - 例如。用于计算满足谓词的元素数的仿函数。此外,使用真实对象的方法作为函子允许您存储它的实例以供以后执行,这是您无法使用构造函数方法的。

从性能pov开始,使用VC和GCC对代码进行了全面优化。但是,更好的策略通常是将仿函数作为参数,这样您就可以获得更多的灵活性和相同的性能特征。

我建议定义使用STL容器的仿函数,即它们应该实现operator()。 (遵循您使用的语言的API总是一个好主意。)

允许你的算法非常通用(传递函数,函子,stl-bind,boost :: function,boost :: bind,boost :: lambda,...)这是人们通常想要的。

这样,您不需要将仿函数类型指定为模板参数,只需构造一个实例并将其传递给:

my_algorithm(foo, bar, MyOperation())

在另一个类中实现构造函数似乎没有任何意义。
你所做的就是打破封装并设置你的课程以便滥用。

构造函数应该将对象初始化为类所定义的良好状态。您允许另一个对象初始化您的类。您有什么保证这个模板类知道如何正确初始化您的类?您的类的用户可以提供任何可能以非预期方式混淆对象内部状态的对象。

该类应该是自包含的,并将自身初始化为良好状态。你似乎正在做的是玩模板只是为了看看他们能做些什么。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top