将功能实现为仿函数的优缺点
Pros and Cons of implementing functionality as functor
我正在与一位同事讨论只有一个 public 方法的简单 class 的 API。我最初去了:
class CalculateSomething
{
public:
void operator()(const SomeObject &obj) const;
private:
// ...
}
然而,我的同事反对使用 operator() 并希望简单地将方法命名为 'calculate' 为了清楚起见。
虽然我觉得这个论点没有说服力,但它让我想到了利弊。
优势运算符()
- class 是精简的,并且有一个明确定义的目的。一旦实例化,它基本上充当一个自由函数。
- 它是一个仿函数,可以很容易地使用(例如 STL 算法)。
- 将其与范围算法一起使用时,可以直接传递对象而不是通过函数指针,这使编译器能够内联代码。虽然不能保证,但通过函数指针传递它完全抑制了这种可能性。
缺点运算符()
- 如果不查看 class 名称,则不太清楚该方法的作用。 (我个人不同意,因为 class 只有一种方法,因此从 class 名称中可以清楚地看出它的含义)
- STL 中的大多数函子都应该是无状态的。我认为这是阻碍我前进的主要原因...
我很惊讶地发现我对此的搜索并没有带来太多结果,因为我认为这是很常见的情况(一个 class,一个责任)。因此,我真的很想听听其他人对此的看法。
如果 lambda 确实 不是一个选项,您的选择应该取决于对象承担的工作范围...以及您的编码约定或风格。您可以决定显式(参见 的回答),如果该方法相对不熟悉并且需要状态,这是一件好事,但是
让我们从标准库中获取简单的用例...
你看到的所有这些的共同点是它们是 动词...在我看来,如果你的 class 与你发布的片段完全一样, CalculateSomething
对我来说意味着一个动作,所以我总是可以将它实例化为 CalculateSomething()(my_object...)
.
正如您引用的那样,它在使用 STL 算法本身和许多其他 C++ 库时非常方便。 如果你采用你同事的方法,你可能不得不使用 std::binds 和 lambda,因为你想要 'adapt' 一个接口。
示例:
class CalculateSomething
{
public:
void operator()(const SomeObject &obj) const;
private:
// ...
}
class CalculateNothing
{
public:
void calculate(const SomeObject &obj) const;
private:
// ...
}
示例用法是:
std::for_each(container.begin(), container.end(), CalculateSomething());
反对
std::for_each(container.begin(), container.end(), [ c = CalculateNothing()](auto x) { c.calculate(x); });
我想我更喜欢前者。
嗯,这也是我的 5 美分。
首先,如果可能的话,我会简单地使用 lambda 或自由函数。您确定,您需要 class 来满足您的需求吗?
无论如何,假设 class 是必需的。
- 我不太喜欢使用 operator()。也许还有其他评论。
- 可能最好将其重命名为“
SomethingCalculator
” - 它不是一个对象吗?
- 你可以添加一个方法,比如“
DoWork
”、“Calculate
”等等。
这将使它更加明确。
UPD. 以上所有内容仍有争议,但我真正相信的是,添加足够的代码内文档将带来真正的不同,与方法名称无关.
我正在与一位同事讨论只有一个 public 方法的简单 class 的 API。我最初去了:
class CalculateSomething
{
public:
void operator()(const SomeObject &obj) const;
private:
// ...
}
然而,我的同事反对使用 operator() 并希望简单地将方法命名为 'calculate' 为了清楚起见。 虽然我觉得这个论点没有说服力,但它让我想到了利弊。
优势运算符()
- class 是精简的,并且有一个明确定义的目的。一旦实例化,它基本上充当一个自由函数。
- 它是一个仿函数,可以很容易地使用(例如 STL 算法)。
- 将其与范围算法一起使用时,可以直接传递对象而不是通过函数指针,这使编译器能够内联代码。虽然不能保证,但通过函数指针传递它完全抑制了这种可能性。
缺点运算符()
- 如果不查看 class 名称,则不太清楚该方法的作用。 (我个人不同意,因为 class 只有一种方法,因此从 class 名称中可以清楚地看出它的含义)
- STL 中的大多数函子都应该是无状态的。我认为这是阻碍我前进的主要原因...
我很惊讶地发现我对此的搜索并没有带来太多结果,因为我认为这是很常见的情况(一个 class,一个责任)。因此,我真的很想听听其他人对此的看法。
如果 lambda 确实 不是一个选项,您的选择应该取决于对象承担的工作范围...以及您的编码约定或风格。您可以决定显式(参见
让我们从标准库中获取简单的用例...
你看到的所有这些的共同点是它们是 动词...在我看来,如果你的 class 与你发布的片段完全一样, CalculateSomething
对我来说意味着一个动作,所以我总是可以将它实例化为 CalculateSomething()(my_object...)
.
正如您引用的那样,它在使用 STL 算法本身和许多其他 C++ 库时非常方便。 如果你采用你同事的方法,你可能不得不使用 std::binds 和 lambda,因为你想要 'adapt' 一个接口。
示例:
class CalculateSomething
{
public:
void operator()(const SomeObject &obj) const;
private:
// ...
}
class CalculateNothing
{
public:
void calculate(const SomeObject &obj) const;
private:
// ...
}
示例用法是:
std::for_each(container.begin(), container.end(), CalculateSomething());
反对
std::for_each(container.begin(), container.end(), [ c = CalculateNothing()](auto x) { c.calculate(x); });
我想我更喜欢前者。
嗯,这也是我的 5 美分。
首先,如果可能的话,我会简单地使用 lambda 或自由函数。您确定,您需要 class 来满足您的需求吗?
无论如何,假设 class 是必需的。
- 我不太喜欢使用 operator()。也许还有其他评论。
- 可能最好将其重命名为“
SomethingCalculator
” - 它不是一个对象吗? - 你可以添加一个方法,比如“
DoWork
”、“Calculate
”等等。
这将使它更加明确。
UPD. 以上所有内容仍有争议,但我真正相信的是,添加足够的代码内文档将带来真正的不同,与方法名称无关.