Std::function和Std::bind是什么,什么时候应该使用它们

std::function and std::bind: what are they, and when should they be used?

本文关键字:Std function bind 是什么 什么时候      更新时间:2023-10-16

我知道函子是什么,以及什么时候在std算法中使用它们,但我还不明白Stroustrup在c++ 11 FAQ中是怎么说的。

谁能解释一下std::bindstd::function是什么,什么时候应该使用它们,并给新手一些例子?

std::bind为部分函数应用

也就是说,假设你有一个函数对象f,它接受3个参数:
f(a,b,c);

你想要一个只接受两个参数的新函数对象,定义为:

g(a,b) := f(a, 4, b);

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

您可以使用std::bind来获得g:

auto g = bind(f, _1, 4, _2);

这比实际编写一个函函数类更简洁。

在您链接到的文章中有更多的例子。通常在需要向某个算法传递函子时使用它。你有一个函数或函子,几乎完成你想要的工作,但比算法使用的更可配置(即有更多参数)。因此,您可以将实参绑定到一些形参,而将其余的留给算法来填充:

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

这里,pow有两个参数,可以取任意次幂,但我们只关心取7的次幂。

作为非部分函数应用程序的偶尔使用,bind还可以重新排序函数的参数:

auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);

我不建议仅仅因为你不喜欢这个API就使用它,但是它有潜在的实际用途,例如:

not2(bind(less<T>, _2, _1));

是一个小于等于函数(假设一个总顺序,等等)。这个例子通常是不必要的,因为已经有一个std::less_equal(它使用<=操作符而不是<,所以如果它们不一致,那么您可能需要这个操作符,并且您可能还需要访问类的作者。)但是,如果使用函数式编程风格,就会出现这种转换。

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);
    }
};

std::bind在包含boost bind的提议之后被投票加入库,主要是部分函数专门化,其中您可以修复少量参数并动态更改其他参数。这是c++中的函数库方法。Steve Jessop的回答

现在c++ 11支持lambda函数,我不再想使用std::bind了。比起库特性,我更愿意在语言特性上使用柯里化(部分专门化)。

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

我想给你指出这两个链接,以获得更多的细节:

c++ 11中的

Lambda函数:https://www.variadic.xyz/2011/10/12/c11-lambda-having-fun-with-brackets/

c++中

可调用实体:https://www.variadic.xyz/2011/05/31/callable-entity/

我很久以前用它在c++中创建一个插件线程池;因为函数有三个参数,你可以这样写

假设您的方法具有签名:

int CTask::ThreeParameterTask(int par1, int par2, int par3)

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

// 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
};

现在,为了绑定参数,我们必须编写一个绑定函数。所以,它是这样的:

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;
};

和一个使用bind3类的辅助函数- 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);
}

和如何调用

F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3( 
          &CTask::ThreeParameterTask), task1,2122,23 );

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

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