std :: function和std :: bind:它们是什么时候应该使用它们?

Mr.*_*bis 114 c++ stdbind c++11 std-function

我知道什么是仿函数以及何时将它们与stl algos一起使用.但不明白他在这个主题中的意思:

C++ 11FAQ

任何人都可以解释什么是什么std,什么std::bind时候应该使用,新手的一些例子?

Ste*_*sop 179

std::bind用于部分功能应用.

也就是说,假设您有一个带有f3个参数的函数对象:

f(a,b,c);
Run Code Online (Sandbox Code Playgroud)

你想要一个只有两个参数的新函数对象,定义如下:

g(a,b) := f(a, 4, b);
Run Code Online (Sandbox Code Playgroud)

g是函数的"部分应用" f:已经指定了中间参数,还有两个要去.

你可以std::bind用来得到g:

auto g = bind(f, _1, 4, _2);
Run Code Online (Sandbox Code Playgroud)

这比编写仿函数类更简洁.

您链接到的文章中还有其他示例.当您需要将仿函数传递给某些算法时,通常会使用它.你有一个几乎完成你想要的工作的函数或函子,但是比算法使用的更具可配置性(即有更多的参数).因此,您将参数绑定到某些参数,然后让算法的其余部分填写:

// raise every value in vec to the power of 7
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7));
Run Code Online (Sandbox Code Playgroud)

在这里,pow需要两个参数并可以提升到任何功率,但我们关心的是提升到7的幂.

作为不是部分函数应用程序的偶然使用,也bind可以将参数重新排序为函数:

auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);
Run Code Online (Sandbox Code Playgroud)

我不建议仅仅因为您不喜欢API而使用它,但它具有潜在的实际用途,例如:

not2(bind(less<T>, _2, _1));
Run Code Online (Sandbox Code Playgroud)

是一个小于或等于的功能(假设总订单,等等).这个例子通常不是必需的,因为已经存在std::less_equal(它使用<=运算符而不是<,因此,如果它们不一致,那么您可能需要它,并且您可能还需要使用线索访问该类的作者).不过,如果你正在使用一种功能性的编程风格,那就会出现这种转变.

  • 对于成员函数的回调也很方便:`myThread = boost :: thread(boost :: bind(&MyClass :: threadMain,this))` (15认同)
  • 绑定的好解释.但是`std :: function`怎么样? (13认同)
  • 您的`pow`示例无法编译.由于`pow`是一个重载函数,你必须手动指定哪个重载.绑定不能让生成的仿函数的调用者推断它.例如`std :: transform(vec.begin(),vec.end(),out.begin(),std :: bind((double(*)(double,int))std :: pow,_1,7) );` (8认同)
  • 同样,“_1”是指`std::placeholders::_1`。我花了一段时间才找出为什么这不能编译。 (7认同)
  • 解释得很好,但有时`std :: bind`与`this`用法一起作为第二个参数。您能否详细说明该用例? (2认同)
  • @Mendes:如果您绑定的函数是任何类的成员函数,则将 this 用作第二个参数,第三个参数是占位符。 (2认同)
  • @Tiago 这是为什么呢?在这里不使用“auto”将是完全愚蠢的。在第一个示例中,假设“f”是“int f(int,int,int)”,则“g”的类型为“_Bind&lt;int(*(_Placeholder&lt;1&gt;,int,_Placeholder&lt;2&gt;))” (整数,整数,整数)&gt;`。你真的想把它写在你的代码中吗?这会让读者更清楚一些吗?我非常怀疑... (2认同)

Shi*_*hah 13

std :: function和std :: bind的主要用途之一是安全函数指针.您可以使用它来实现回调机制.一个流行的场景是你有一些功能需要很长时间才能执行,但你不想等待它返回然后你可以在单独的线程上运行该函数并给它一个函数指针,它会完成后回调.

这是一个如何使用它的示例代码:

class MyClass {
private:
    //just shorthand to avoid long typing
    typedef std::function<void (float result)> TCallback;

    //this function takes long time
    void longRunningFunction(TCallback callback)
    {
        //do some long running task
        //...
        //callback to return result
        callback(result);
    }

    //this function gets called by longRunningFunction after its done
    void afterCompleteCallback(float result)
    {
        std::cout << result;
    }

public:
    int longRunningFunctionAsync()
    {
        //create callback - this equivalent of safe function pointer
        auto callback = std::bind(&MyClass::afterCompleteCallback, 
            this, std::placeholders::_1);

        //normally you want to start below function on seprate thread, 
        //but for illustration we will just do simple call
        longRunningFunction(callback);
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案。我到处都在寻找这个答案。谢谢@ShitalShah (4认同)
  • @nonock 对于成员函数的函数指针,我们需要传递“this”指针作为第一个参数。 (3认同)

Sar*_*ang 12

std :: bind在提议包含boost绑定后被投票到库中,主要是部分功能专用,其中你可以修复一些参数并在飞行中更改其他参数.现在这是用C++编写lambda的库方式.正如Steve Jessop所回答的那样

既然C++ 11支持lambda函数,我再也不觉得使用std :: bind了.我宁愿使用语言特征的currying(部分特化)而不是库特征.

std :: function对象是多态函数.基本思想是能够互换地引用所有可调用对象.

我会指出这两个链接以获取更多详细信息:

Lambda函数在C++ 11中的应用:http: //www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8

C++中的可调用实体:http: //www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8

  • `std :: bind`在没有lambdas的情况下从未存在过 - 这两个特性都是在C++ 11中引入的.我们确实有`bind1st`和`bind2nd`这些是C++ 11 bind的瘦弱版本. (4认同)

Ale*_*nen 5

我用了很长时间回来用C++创建一个插件线程池; 由于函数有三个参数,你可以像这样写

假设您的方法具有签名:

int CTask::ThreeParameterTask(int par1, int par2, int par3)
Run Code Online (Sandbox Code Playgroud)

要创建一个函数对象来绑定三个参数,您可以这样做

// a template class for converting a member function of the type int function(int,int,int)
//to be called as a function object
template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3>
class mem_fun3_t
{
public:
    explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3))
        :m_Ptr(_Pm) //okay here we store the member function pointer for later use
    {}

    //this operator call comes from the bind method
    _Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const
    {
        return ((_P->*m_Ptr)(arg1,arg2,arg3));
    }
private:
    _Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature
};
Run Code Online (Sandbox Code Playgroud)

现在,为了绑定参数,我们必须编写一个binder函数.所以,在这里:

template<typename _Func,typename _Ptr,typename _arg1,typename _arg2,typename _arg3>
class binder3
{
public:
    //This is the constructor that does the binding part
    binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k)
        :m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){}


        //and this is the function object 
        void operator()() const
        {
            m_fn(m_ptr,m1,m2,m3);//that calls the operator
        }
private:
    _Ptr m_ptr;
    _Func m_fn;
    _arg1 m1; _arg2 m2; _arg3 m3;
};
Run Code Online (Sandbox Code Playgroud)

并且,使用binder3类的辅助函数 - bind3:

//a helper function to call binder3
template <typename _Func, typename _P1,typename _arg1,typename _arg2,typename _arg3>
binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k)
{
    return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k);
}
Run Code Online (Sandbox Code Playgroud)

在这里我们如何称呼它

F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3( 
          &CTask::ThreeParameterTask), task1,2122,23 );
Run Code Online (Sandbox Code Playgroud)

注意:f3(); 将调用方法task1-> ThreeParameterTask(21,22,23);

有关更多详细信息 - > http://www.codeproject.com/Articles/26078/AC-Plug-in-ThreadPool-Design