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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6610046/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:25:48  来源:igfitidea点击:

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

c++c++11std-functionstdbind

提问by Mr.Anubis

I know what functors are and when to use them with stdalgorithms, but I haven't understood what Stroustrup says about them in the C++11 FAQ.

我知道函子是什么以及何时将它们与std算法一起使用,但我不明白 Stroustrup 在C++11 FAQ 中对它们所说的内容。

Can anyone explain what std::bindand std::functionare, when they should be used, and give some examples for newbies?

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

回答by Steve Jessop

std::bindis for partial function application.

std::bind用于偏函数应用

That is, suppose you have a function object fwhich takes 3 arguments:

也就是说,假设您有一个f接受 3 个参数的函数对象:

f(a,b,c);

You want a new function object which only takes two arguments, defined as:

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

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

gis a "partial application" of the function f: the middle argument has already been specified, and there are two left to go.

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

You can use std::bindto get g:

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

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

This is more concise than actually writing a functor class to do it.

这比实际编写一个函子类来做到这一点更简洁。

There are further examples in the article you link to. You generally use it when you need to pass a functor to some algorithm. You have a function or functor that almostdoes the job you want, but is more configurable (i.e. has more parameters) than the algorithm uses. So you bind arguments to some of the parameters, and leave the rest for the algorithm to fill in:

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

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

Here, powtakes two parameters and can raise to anypower, but all we care about is raising to the power of 7.

这里,pow有两个参数,可以提升到任意次方,但我们关心的只是提升到 7 的次方。

As an occasional use that isn't partial function application, bindcan also re-order the arguments to a function:

作为不属于偏函数应用的偶尔使用,bind还可以对函数的参数重新排序:

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

I don't recommend using it just because you don't like the API, but it has potential practical uses for example because:

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

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

is a less-than-or-equal function (assuming a total order, blah blah). This example normally isn't necessary since there already is a std::less_equal(it uses the <=operator rather than <, so if they aren't consistent then you might need this, and you might also need to visit the author of the class with a cluestick). It's the sort of transformation that comes up if you're using a functional style of programming, though.

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

回答by Shital Shah

One of the main use of std::function and std::bind is as more generelized function pointers. You can use it to implement callback mechanism. One of the popular scenario is that you have some function that is going to take long time to execute but you don't want to wait for it to return then you can run that function on separate thread and give it a function pointer that it will callback after it completes.

std::function 和 std::bind 的主要用途之一是作为更通用的函数指针。您可以使用它来实现回调机制。一种流行的情况是,您有一些函数需要很长时间才能执行,但您不想等待它返回,然后您可以在单独的线程上运行该函数并为其提供一个函数指针完成后回调。

Here's a sample code for how to use this:

这是有关如何使用它的示例代码:

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

回答by Sarang

std::bind was voted into library after proposal to include boost bind, primarily it is partial function specialization where-in you can fix few parameters and change others on fly. Now this is library way of doing lambdas in C++. As answered by Steve Jessop

std::bind 在提议包含 boost bind 后被选入库,主要是它是部分函数专业化,其中您可以修复很少的参数并动态更改其他参数。现在这是在 C++ 中执行 lambdas 的库方式。正如史蒂夫·杰索普 (Steve Jessop) 所回答

Now that C++11 supports lambda functions I don't feel any temptation to use std::bind anymore. I would rather use currying (partial specialization) with language feature than library feature.

现在 C++11 支持 lambda 函数,我不再觉得有任何使用 std::bind 的诱惑。我宁愿使用具有语言功能的柯里化(部分专业化)而不是库功能。

std::function objects are polymorphic functions. The basic idea is to be able to refer to all the callable objects interchangeably.

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

I would point you to these two links for further details:

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

Lambda functions in C++11: http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8

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

Callable entity in C++: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8

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

回答by Alex Punnen

I used it long time back to create a plugin thread pool in C++ ; Since the function was taking three parameters you can write like this

我很久以前就用它在 C++ 中创建了一个插件线程池;由于该函数采用三个参数,因此您可以这样编写

Suppose your method has the signature:

假设您的方法具有签名:

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

To create a function object to bind the three parameters you can do like this

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

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

Now, in order to bind the parameters, we have to write a binder function. So, here it goes:

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

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

And, a helper function to use the binder3 class - bind3:

并且,一个使用 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);
}

and here us how to call it

在这里我们如何称呼它

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

Note: f3(); will call the method task1->ThreeParameterTask(21,22,23);

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

For more gory details --> http://www.codeproject.com/Articles/26078/A-C-Plug-in-ThreadPool-Design

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