I keep hearing a lot about functors in C++. Can someone give me an overview as to what they are and in what cases they would be useful?
相关问题
- Sorting 3 numbers without branching [closed]
- How to compile C++ code in GDB?
- Why does const allow implicit conversion of refere
- thread_local variables initialization
- What uses more memory in c++? An 2 ints or 2 funct
相关文章
- Class layout in C++: Why are members sometimes ord
- How to mock methods return object with deleted cop
- Which is the best way to multiply a large and spar
- C++ default constructor does not initialize pointe
- Selecting only the first few characters in a strin
- What exactly do pointers store? (C++)
- Converting glm::lookat matrix to quaternion and ba
- What is the correct way to declare and use a FILE
Little addition. You can use
boost::function
, to create functors from functions and methods, like this:and you can use boost::bind to add state to this functor
and most useful, with boost::bind and boost::function you can create functor from class method, actually this is a delegate:
You can create list or vector of functors
There is one problem with all this stuff, compiler error messages is not human readable :)
A big advantage of implementing functions as functors is that they can maintain and reuse state between calls. For example, many dynamic programming algorithms, like the Wagner-Fischer algorithm for calculating the Levenshtein distance between strings, work by filling in a large table of results. It's very inefficient to allocate this table every time the function is called, so implementing the function as a functor and making the table a member variable can greatly improve performance.
Below is an example of implementing the Wagner-Fischer algorithm as a functor. Notice how the table is allocated in the constructor, and then reused in
operator()
, with resizing as necessary.A functor is pretty much just a class which defines the operator(). That lets you create objects which "look like" a function:
There are a couple of nice things about functors. One is that unlike regular functions, they can contain state. The above example creates a function which adds 42 to whatever you give it. But that value 42 is not hardcoded, it was specified as a constructor argument when we created our functor instance. I could create another adder, which added 27, just by calling the constructor with a different value. This makes them nicely customizable.
As the last lines show, you often pass functors as arguments to other functions such as std::transform or the other standard library algorithms. You could do the same with a regular function pointer except, as I said above, functors can be "customized" because they contain state, making them more flexible (If I wanted to use a function pointer, I'd have to write a function which added exactly 1 to its argument. The functor is general, and adds whatever you initialized it with), and they are also potentially more efficient. In the above example, the compiler knows exactly which function
std::transform
should call. It should calladd_x::operator()
. That means it can inline that function call. And that makes it just as efficient as if I had manually called the function on each value of the vector.If I had passed a function pointer instead, the compiler couldn't immediately see which function it points to, so unless it performs some fairly complex global optimizations, it'd have to dereference the pointer at runtime, and then make the call.
I have "discovered" a very interesting use of functors: I use them when I have not a good name for one method, as a functor is a method without name ;-)
Like others have mentioned, a functor is an object that acts like a function, i.e. it overloads the function call operator.
Functors are commonly used in STL algorithms. They are useful because they can hold state before and between function calls, like a closure in functional languages. For example, you could define a
MultiplyBy
functor that multiplies its argument by a specified amount:Then you could pass a
MultiplyBy
object to an algorithm like std::transform:Another advantage of a functor over a pointer to a function is that the call can be inlined in more cases. If you passed a function pointer to
transform
, unless that call got inlined and the compiler knows that you always pass the same function to it, it can't inline the call through the pointer.A functor is a higher-order function that applies a function to the parametrized(ie templated) types. It is a generalization of the map higher-order function. For example, we could define a functor for
std::vector
like this:This function takes a
std::vector<T>
and returnsstd::vector<U>
when given a functionF
that takes aT
and returns aU
. A functor doesn't have to be defined over container types, it can be defined for any templated type as well, includingstd::shared_ptr
:Heres a simple example that converts the type to a
double
:There are two laws that functors should follow. The first is the identity law, which states that if the functor is given an identity function, it should be the same as applying the identity function to the type, that is
fmap(identity, x)
should be the same asidentity(x)
:The next law is the composition law, which states that if the functor is given a composition of two functions, it should be the same as applying the functor for the first function and then again for the second function. So,
fmap(std::bind(f, std::bind(g, _1)), x)
should be the same asfmap(f, fmap(g, x))
: