Sometimes I tend to write functors, not for the sake of maintaining state between function calls, but because I want to capture some arguments that are shared between function calls. As an example:
class SuperComplexAlgorithm
{
public:
SuperComplexAlgorithm( unsigned int x, unsigned int y, unsigned int z )
: x_( x ), y_( y ), z_( z )
{}
unsigned int operator()( unsigned int arg ) const /* yes, const! */
{
return x_ * arg * arg + y_ * arg + z_;
}
private:
// Lots of parameters are stored as member variables.
unsigned int x_, y_, z_;
};
// At the call site:
SuperComplexAlgorithm a( 3, 4, 5 );
for( unsigned int i = 0; i < 100; ++i )
do_stuff_with( a ); // or whatever
Compared to
unsigned int superComplexAlgorithm( unsigned int x, unsigned int y,
unsigned int z, unsigned int arg )
{
return x * arg * arg + y * arg + z;
}
// At the call site:
auto a = std::bind( superComplexAlgorithm, 3, 4, 5, std::placeholders::_1 );
for( unsigned int i = 0; i < 100; ++i )
do_stuff_with( a );
the first solution has a lot of drawbacks, in my opinion:
x
, y
, z
do is split at different places (constructor, class definition, operator()
).Yes, I just realized how useful boost::bind
or std::bind
can be. Now for my question before I start using this in a lot of my code: Is there any situation where I should consider using a hand-written stateless functor over binding arguments in a plain function?
The lambda solution would be the idomatic C++11 way:
auto a = [&]( int x ){ return superComplexAlgorithm( 3, 4, 5, x ); };
for( unsigned int i = 0; i < 100; ++i )
do_stuff_with( a );
The advantage of using a hand written functor is that you can:
bind
)auto
) -- the same is true of bind
, but it also has a non-anonymous meaningful type you can get at without decltype
ing the entire expression! C++1y again makes this better for bind
/lambda.bind
does this)You can also do some extremely powerful things with hand written functors that are impossible to do with bind
and lambdas, like wrap an overload set of multiple functions into one object (that may or may not share a name), but that kind of corner case isn't going to show up often.