C++ 为什么要覆盖 operator()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/317450/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:35:30  来源:igfitidea点击:

Why override operator()?

c++boostoperator-overloadingfunctorfunction-call-operator

提问by JeffV

In the Boost Signalslibrary, they are overloading the () operator.

Boost Signals库中,它们重载了 () 运算符。

Is this a convention in C++? For callbacks, etc.?

这是 C++ 中的约定吗?对于回调等?

I have seen this in code of a co-worker (who happens to be a big Boost fan). Of all the Boost goodness out there, this has only led to confusion for me.

我在一位同事的代码中看到了这一点(他恰好是 Boost 的忠实粉丝)。在所有 Boost 优点中,这只会让我感到困惑。

Any insight as to the reason for this overload?

关于这种超载的原因有什么见解吗?

回答by Luc Touraille

One of the primary goal when overloading operator() is to create a functor. A functor acts just like a function, but it has the advantages that it is stateful, meaning it can keep data reflecting its state between calls.

重载 operator() 的主要目标之一是创建一个函子。函子的行为就像一个函数,但它的优点是它是有状态的,这意味着它可以在调用之间保留反映其状态的数据。

Here is a simple functor example :

这是一个简单的函子示例:

struct Accumulator
{
    int counter = 0;
    int operator()(int i) { return counter += i; }
}
...
Accumulator acc;
cout << acc(10) << endl; //prints "10"
cout << acc(20) << endl; //prints "30"

Functors are heavily used with generic programming. Many STL algorithms are written in a very general way, so that you can plug-in your own function/functor into the algorithm. For example, the algorithm std::for_each allows you to apply an operation on each element of a range. It could be implemented something like that :

泛型编程大量使用函子。许多 STL 算法都是以非常通用的方式编写的,因此您可以将自己的函数/函子插入算法中。例如,算法 std::for_each 允许您对范围的每个元素应用操作。它可以实现如下:

template <typename InputIterator, typename Functor>
void for_each(InputIterator first, InputIterator last, Functor f)
{
    while (first != last) f(*first++);
}

You see that this algorithm is very generic since it is parametrized by a function. By using the operator(), this function lets you use either a functor or a function pointer. Here's an example showing both possibilities :

你会看到这个算法非常通用,因为它是由一个函数参数化的。通过使用 operator(),该函数允许您使用函子或函数指针。这是一个显示两种可能性的示例:

void print(int i) { std::cout << i << std::endl; }
...    
std::vector<int> vec;
// Fill vec

// Using a functor
Accumulator acc;
std::for_each(vec.begin(), vec.end(), acc);
// acc.counter contains the sum of all elements of the vector

// Using a function pointer
std::for_each(vec.begin(), vec.end(), print); // prints all elements


Concerning your question about operator() overloading, well yes it is possible. You can perfectly write a functor that has several parentheses operator, as long as you respect the basic rules of method overloading (e.g. overloading only on the return type is not possible).

关于您关于 operator() 重载的问题,是的,这是可能的。只要您遵守方法重载的基本规则(例如,仅在返回类型上重载是不可能的),您就可以完美地编写具有多个括号运算符的函子。

回答by Lodle

It allows a class to act like a function. I have used it in a logging class where the call should be a function but i wanted the extra benefit of the class.

它允许一个类像一个函数一样工作。我在日志类中使用了它,其中调用应该是一个函数,但我想要该类的额外好处。

so something like this:

所以像这样:

logger.log("Log this message");

turns into this:

变成这样:

logger("Log this message");

回答by Mark Ransom

Many have answered that it makes a functor, without telling one big reason why a functor is better than a plain old function.

许多人回答说它是一个函子,但没有说明为什么函子比普通的旧函数更好的一个重要原因。

The answer is that a functor can have state. Consider a summing function - it needs to keep a running total.

答案是函子可以有状态。考虑一个求和函数——它需要保持一个运行总数。

class Sum
{
public:
    Sum() : m_total(0)
    {
    }
    void operator()(int value)
    {
        m_total += value;
    }
    int m_total;
};

回答by Joris Timmermans

A functor is not a function, so you cannot overload it.
Your co-worker is correct though that the overloading of operator() is used to create "functors" - objects that can be called like functions. In combination with templates expecting "function-like" arguments this can be quite powerful because the distinction between an object and a function becomes blurred.

函子不是函数,所以你不能重载它。
您的同事是正确的,尽管 operator() 的重载用于创建“函子”——可以像函数一样调用的对象。结合期望“类函数”参数的模板,这可能非常强大,因为对象和函数之间的区别变得模糊。

As other posters have said: functors have an advantage over plain functions in that they can have state. This state can be used over a single iteration (for example to calculate the sum of all elements in a container) or over multiple iterations (for example to find all elements in multiple containers satisfying particular criteria).

正如其他海报所说:函子比普通函数有优势,因为它们可以有状态。此状态可用于单次迭代(例如计算容器中所有元素的总和)或多次迭代(例如查找满足特定条件的多个容器中的所有元素)。

回答by carson

You may also look over the C++ faq's Matrix example. There are good uses for doing it but it of course depends on what you are trying to accomplish.

您还可以查看C++ 常见问题解答的 Matrix 示例。这样做有很好的用途,但这当然取决于您要完成的工作。

回答by Michel

Start using std::for_each, std::find_if, etc. more often in your code and you'll see why it's handy to have the ability to overload the () operator. It also allows functors and tasks to have a clear calling method that won't conflict with the names of other methods in the derived classes.

开始在您的代码中更频繁地使用std::for_eachstd::find_if等,您就会明白为什么重载 () 运算符的能力很方便。它还允许函子和任务有一个明确的调用方法,不会与派生类中的其他方法的名称冲突。

回答by Greg Rogers

Functors are basically like function pointers. They are generally intended to be copyable (like function pointers) and invoked in the same way as function pointers. The main benefit is that when you have an algorithm that works with a templated functor, the function call to operator() can be inlined. However, function pointers are still valid functors.

函子基本上就像函数指针。它们通常是可复制的(如函数指针)并以与函数指针相同的方式调用。主要的好处是当你有一个使用模板函子的算法时,可以内联对 operator() 的函数调用。然而,函数指针仍然是有效的函子。

回答by Judge Maygarden

The use of operator() to form functorsin C++ is related to functional programmingparadigms that usually make use of a similar concept: closures.

在 C++ 中使用 operator() 形成函子与通常使用类似概念的函数式编程范式有关:闭包

回答by Statement

One strength I can see, however this can be discussed, is that the signature of operator() looks and behaves the same across different types. If we had a class Reporter which had a member method report(..), and then another class Writer, which had a member method write(..), we would have to write adapters if we would like to use both classes as perhaps a template component of some other system. All it would care about is to pass on strings or what have you. Without the use of operator() overloading or writing special type adapters, you couldn't do stuff like

我可以看到的一个优点是,operator() 的签名在不同类型中的外观和行为都相同,但可以对此进行讨论。如果我们有一个 Reporter 类,它有一个成员方法 report(..),然后是另一个 Writer 类,它有一个成员方法 write(..),如果我们想同时使用这两个类,我们就必须编写适配器某个其他系统的模板组件。它所关心的只是传递字符串或你有什么。如果不使用 operator() 重载或编写特殊类型的适配器,你就不能做这样的事情

T t;
t.write("Hello world");

because T has a requirement that there is a member function called write which accepts anything implicitly castable to const char* (or rather const char[]). The Reporter class in this example doesn't have that, so having T (a template parameter) being Reporter would fail to compile.

因为 T 要求有一个名为 write 的成员函数,它接受任何可隐式转换为 const char*(或者更确切地说是 const char[])的内容。此示例中的 Reporter 类没有那个,因此将 T(模板参数)作为 Reporter 将无法编译。

However, as far I can see this would work with different types

但是,据我所知,这适用于不同类型

T t;
t("Hello world");

though, it still explicitly requires that the type T has such an operator defined, so we still have a requirement on T. Personally, I don't think it's too wierd with functors as they are commonly used but I would rather see other mechanisms for this behavior. In languages like C# you could just pass in a delegate. I am not too familiar with member function pointers in C++ but I could imagine you could achieve the same behaviour there aswell.

尽管如此,它仍然明确要求类型 T 定义了这样一个运算符,所以我们仍然对 T 有要求。就我个人而言,我认为函子并不太奇怪,因为它们是常用的,但我更愿意看到其他机制这种行为。在像 C# 这样的语言中,你可以只传递一个委托。我对 C++ 中的成员函数指针不太熟悉,但我可以想象你也可以在那里实现相同的行为。

Other than syntatic sugar behaviour I don't really see the strengths of operator overloading to perform such tasks.

除了语法糖行为之外,我并没有真正看到运算符重载执行此类任务的优势。

I am sure there are more knowingly people who have better reasons than I have but I thought I'd lay out my opinion for the rest of you to share.

我相信有更多明知故犯的人比我有更好的理由,但我想我会提出我的意见供大家分享。

回答by Mr Fooz

Other posts have done a good job describing how operator() works and why it can be useful.

其他帖子很好地描述了 operator() 的工作原理以及它为什么有用。

I've recently been using some code that makes very extensive use of operator(). A disadvantage of overloading this operator is that some IDEs become less effective tools as a result. In Visual Studio, you can usually right-click on a method call to go to the method definition and/or declaration. Unfortunately, VS isn't smart enough to index operator() calls. Especially in complex code with overridden operator() definitions all over the place, it can be very difficult to figure out what piece of code is executing where. In several cases, I found I had to run the code and trace through it to find what was actually running.

我最近一直在使用一些非常广泛使用 operator() 的代码。重载此运算符的一个缺点是,某些 IDE 会因此成为效率较低的工具。在 Visual Studio 中,您通常可以右键单击方法调用以转到方法定义和/或声明。不幸的是,VS 不够聪明,无法索引 operator() 调用。尤其是在到处都覆盖了 operator() 定义的复杂代码中,很难弄清楚哪段代码在何处执行。在一些情况下,我发现我必须运行代码并跟踪它才能找到实际运行的内容。