实现作为仿函数的功能的优点和缺点

OnM*_*uck 12 c++ oop functor design-guidelines

我正在和一位同事讨论一个只有一个公共方法的简单类的API.我最初去了:

class CalculateSomething
{
public:
  void operator()(const SomeObject &obj) const;

private:
  // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,我的同事反对使用operator(),并且为了清楚起见,希望简单地将方法命名为'calculate'.虽然我没有发现这个论点令人信服,但它让我想到了利弊.

优势运营商()

  • 这门课程很精简,有一个明确的目的.一旦实例化,它基本上充当自由函数.
  • 它是一个仿函数,可以很容易地使用(例如STL算法).
  • 当使用范围算法时,可以直接传递对象而不是通过函数指针,这使编译器能够内联代码.虽然不能保证,但通过函数指针完全禁止这种可能性.

缺点operator()

  • 如果不查看类名,该方法的作用就不太清楚了.(我个人不同意,因为班级只有一种方法,因此从班级名称中明确其含义)
  • 预计STL中的大多数算子都是无国籍的.我认为这是阻碍我的主要原因......

我很惊讶地看到我对此的搜索并没有带来太大的影响,因为我认为这是一个非常常见的情况(一类,一类责任).因此,我真的很想听听其他人对此的看法.

Whi*_*TiM 3

如果 lambda确实不是一个选择,那么您的选择应该取决于对象承担的工作范围......以及您的编码约定或风格。您可以决定明确(参见Werolik的回答),如果该方法相对不熟悉并且需要状态,那么这是一件好事,但是

让我们从标准库中获取简单的用例......

  • std::hash:这是一个只做一项工作的函数对象,并且据说做得很好,对此没有争议
  • 还有更多...包括std::less及其分类

您看到的所有这些的共同点是它们都是动词......在我看来,如果您的类与您发布的片段完全相同,则CalculateSomething对我来说意味着一个动作,所以我总是可以将其实例化为CalculateSomething()(my_object...)。

正如您所引用的,它在使用 STL 算法本身和许多其他 C++ 库时非常方便。如果您采用同事的方法,您可能不得不求助于使用 std::binds 和 lambda,因为您想要“适应”接口。

例子:

class CalculateSomething
{
    public:
         void operator()(const SomeObject &obj) const;
    private:
         // ...
}

class CalculateNothing
{
    public:
         void calculate(const SomeObject &obj) const;
    private:
         // ...
}
Run Code Online (Sandbox Code Playgroud)

一个示例用法是:

std::for_each(container.begin(), container.end(), CalculateSomething());
Run Code Online (Sandbox Code Playgroud)

反对

std::for_each(container.begin(), container.end(), [ c = CalculateNothing()](auto x) { c.calculate(x); });
Run Code Online (Sandbox Code Playgroud)

我想我更喜欢前者。