有时我倾向于编写仿函数,不是为了在函数调用之间维护状态,而是因为我想捕获函数调用之间共享的一些参数。举个例子:
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
与
相比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 );
第一种解决方案在我看来有许多缺点:
x
,y
,z
所做的文档在不同的地方分开(构造函数,类定义,operator()
)。是的,我刚刚意识到boost::bind
或std::bind
有多么有用。现在在我开始在我的很多代码中使用它之前的问题:是否有任何情况我应该考虑在普通函数中使用手写的无状态函子来绑定参数?
答案 0 :(得分:8)
lambda解决方案将是自动的C ++ 11方式:
auto a = [&]( int x ){ return superComplexAlgorithm( 3, 4, 5, x ); };
for( unsigned int i = 0; i < 100; ++i )
do_stuff_with( a );
使用手写的仿函数的好处是你可以:
bind
也可以这样做)auto
的情况下讨论该类型) - bind
也是如此,但它也有非匿名你可以在没有decltype
整个表达式的情况下获得有意义的类型! C ++ 1y再次使bind
/ lambda。bind
执行此操作)你也可以使用bind
和lambdas无法做的手写编写器来做一些非常强大的事情,比如将一组多个函数的重载包装到一个对象中(可能有也可能不共享一个名字)但是这种角落的情况不会经常出现。
答案 1 :(得分:4)
是否有任何情况我应该考虑在普通函数中使用手写无状态函子来绑定参数?
来自评论:
我不想在调用站点定义superComplexAlgorithm,因为它非常复杂,在很多地方使用,需要测试和文档等。
如果superComplexAlgorithm
的实现需要一堆代码,并且最终将它拆分为带有大量参数的不同函数,那么最好使用一个提供跨共享状态的类。内部实施功能。除了那个角落的情况,std::bind
的行为将等同于你在问题中提供的仿函数。
有些说明,因为您提到boost::bind
和std::bind
作为替代方案。您可能想测试您的实现的功能。例如,使用boost 1.35(古代),bind
操作将为每个参数创建4个副本,VS2010将在std::bind
中创建7个副本,尽管gcc 4.7中的std::bind
仅执行1个。参数很小,不会产生很高的成本,但如果你正在进行操作,或者你的对象复制成本很高......只需要测量。
关于lambda,如果性能是一个问题,也要衡量它的行为方式。它应该制作一份副本。如果性能不是问题,那么lambda在捕获的内容上就不那么明确(用户需要读取lambda的实现来解决这个问题),甚至查看代码也可能不那么明显。 / p>