0

我正在使用 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)" ,但这可能只是美观。

4

5 回答 5

2

有什么缺点吗?

  • Tors 不返回任何有用的值——不能在链式调用中使用(例如 foo(bar())。
  • 他们可以扔。
  • 设计观点——ctors 是对象创建函数,并不是真正的主力。
于 2009-03-07T16:22:14.250 回答
1
  1. 编译器实际上内联了 Operation 的空构造函数(至少 gcc 在类似情况下会这样做,除非您关闭优化)
  2. 在构造函数中做所有事情的缺点是您不能以这种方式创建具有某种内部状态的函子 - 例如。用于计算满足谓词的元素数量的函子。此外,使用真实对象的方法作为函子允许您存储它的实例以供以后执行,这是您的构造函数方法无法做到的。
于 2009-03-07T16:21:56.873 回答
1

从性能方面来看,演示的代码使用 VC 和 GCC 进行了完全优化。然而,更好的策略通常是将函子作为参数,这样您可以获得更多的灵活性和相同的性能特征。

于 2009-03-07T16:30:48.223 回答
0

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

这使您的算法非常通用(传入函数、仿函数、stl-bind、boost::function、boost::bind、boost::lambda,...),这是人们通常想要的。

这样,就不需要将仿函数类型指定为模板参数,只需构造一个实例并传入即可:

my_algorithm(foo, bar, MyOperation())
于 2009-03-07T17:32:47.810 回答
0

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

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

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

于 2009-03-08T12:52:31.737 回答