C++ 函子与std::bind

C++ 函子与std::bind,c++,c++11,boost-bind,C++,C++11,Boost Bind,有时我倾向于编写functor,不是为了维护函数调用之间的状态,而是因为我想捕获函数调用之间共享的一些参数。例如: class SuperComplexAlgorithm { public: SuperComplexAlgorithm( unsigned int x, unsigned int y, unsigned int z ) : x_( x ), y_( y ), z_( z ) {} unsigned i

有时我倾向于编写functor,不是为了维护函数调用之间的状态,而是因为我想捕获函数调用之间共享的一些参数。例如:

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
类超复数算法
{
公众:
超复数算法(无符号整数x,无符号整数y,无符号整数z)
:x_ux,y_ux,z_z
{}
unsigned int operator()(unsigned int arg)const/*是,const*/
{
返回x_*arg*arg+y_*arg+z;
}
私人:
//许多参数存储为成员变量。
无符号整数x,y,z;
};
//在呼叫站点:
超复形算法a(3,4,5);
for(无符号整数i=0;i<100;++i)
用(a);//或者别的什么
相比

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,无符号整数arg)
{
返回x*arg*arg+y*arg+z;
}
//在呼叫站点:
自动a=std::bind(超级复杂算法,3,4,5,std::占位符::_1);
for(无符号整数i=0;i<100;++i)
用(a)做东西;
在我看来,第一种解决方案有很多缺点:

  • 关于
    x
    y
    z
    所做的事情的文档在不同的位置被分割(构造函数、类定义、
    操作符()
  • 很多锅炉铭牌代码
  • 不太灵活。如果我想捕获不同的参数子集,该怎么办

是的,我刚刚意识到
boost::bind
std::bind
是多么有用。在我开始在我的代码中使用这个问题之前,我想问一下:在任何一种情况下,我应该考虑使用手写无状态函子来代替普通函数中的绑定参数吗?< /P> < P> LAMBDA解决方案将是IdC++ 11方式:

auto a = [&]( int x ){ return superComplexAlgorithm( 3, 4, 5, x ); };
for( unsigned int i = 0; i < 100; ++i )
  do_stuff_with( a );
autoa=[&](intx){返回超复数算法(3,4,5,x);};
for(无符号整数i=0;i<100;++i)
用(a)做东西;
使用手写函子的优点是可以:

  • 将参数移动到捕获中,或对其进行转换(您可以在C++1y中使用lambda来实现这一点,但目前还不能——使用
    bind
    也可以实现这一点)
  • 它有一个非匿名类型(因此您可以在不使用
    auto
    的情况下谈论该类型)-
    bind
    也是如此,但它也有一个非匿名的有意义的类型,您可以在不使用
    decltype
    的情况下获取整个表达式!C++1y再次为
    bind
    /lambda提供了更好的性能
  • 您可以完美地转发剩余的参数(您可能可以在C++1y中使用lambda实现这一点,
    bind
    可以做到这一点)
  • 您可以搞乱捕获数据的存储方式(在指针?智能指针?)而不会搞乱创建实例的代码
  • 您还可以使用手工编写的函子来完成一些功能极其强大的任务,这些函子是使用
    bind
    和lambdas无法完成的,例如将多个函数的重载集包装到一个对象中(可以共享名称,也可以不共享名称),但这种情况不会经常出现

    是否有任何情况下我应该考虑在一个普通函数中使用一个手写无状态函子来约束参数?< /P> 从评论中:

    我不想在调用站点定义超级复杂算法,因为它是超级复杂的,在很多地方使用,需要测试和文档等

    如果
    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的实现才能弄清楚这一点),甚至看代码也不那么明显。lambdas@stijn:我不想在调用站点定义
    superComplexAlgorithm
    ,因为它非常复杂,在很多地方都使用,需要测试和文档等。。我看不出lambda在这种情况下有什么帮助,尽管我在其他情况下经常使用它们。@MarkusMayr,您可以用lambda替换
    std::bind
    。你不是写
    std::bind(超级复杂算法,3,4,5,std::占位符::_1)
    ,而是写
    [](int x){返回超级复杂算法(3,4,5,x);
    。自从lambdas对我可用以来,我从未使用过
    bind
    或重载
    操作符()
    。因此,不,我无法想象这样的情况:)将代码放入lambda或编写一个函数并从lambda调用它。我想指出,此模式的“官方”名称是。为什么在lambda中有一个capture子句?除非您确实需要捕获某些内容,否则不应该使用捕获。如果根本没有捕获,为什么要通过引用捕获?@sebastianredl它与bind类似:通常绑定的值不是编译时常量,或者y