std :: function和std :: bind:它们是什么时候应该使用?
我知道函数是什么,什么时候使用它们与stl算术。 但不明白他在这个话题中的含义:
C ++ 11FAQ
任何一个可以解释什么std::bind
和std::function
是什么时候应该使用,一些新手的例子?
std::bind
用于部分函数应用程序 。
也就是说,假设你有一个带有3个参数的函数对象f
:
f(a,b,c);
你需要一个只有两个参数的新的函数对象,定义如下:
g(a,b) := f(a, 4, b);
g
是函数的“部分应用” f
:已经指定了中间参数,剩下两个参数。
你可以使用std::bind
来获取g
:
auto g = bind(f, _1, 4, _2);
这比编写一个函子类来做得更简洁。
您链接到的文章中还有其他示例。 当你需要传递一个函子给某个algorithm时,你通常会使用它。 你有一个函数或仿函数几乎完成你想要的工作,但是比algorithm使用更多的configuration(即有更多的参数)。 所以你将参数绑定到一些参数上,剩下的部分用来填充algorithm:
// 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
也可以重新sorting函数的参数:
auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);
我不build议仅仅因为您不喜欢API而使用它,但是它有潜在的实际用途,例如:
not2(bind(less<T>, _2, _1));
是一个小于或等于的函数(假设总的顺序,等等等等)。 这个例子通常是没有必要的,因为已经有一个std::less_equal
(它使用<=
运算符而不是<
,所以如果他们不一致,那么你可能需要这个,你可能还需要访问的作者class级与cluestick)。 不过,如果你使用了一种function性的编程风格,就会出现这种转变。
build议将std :: bind投入到库中,以便包含boost绑定,主要是部分函数特化,在这里你可以修复一些参数,并且可以修改其他参数。 现在这是在C ++中使用lambdaexpression式的库方法。 正如Steve Jessop回答的那样
既然C ++ 11支持lambda函数,那么我就不会再有使用std :: bind的诱惑了。 我宁愿使用具有语言特征的库里(部分专业化)而不是库特征。
std :: function对象是多态函数。 基本思想是能够互换地引用所有的可调用对象。
我会告诉你这两个链接的进一步细节:
C ++ 11中的Lambda函数: 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
我很久以前用C ++创build一个插件线程池。 由于该function是三个参数,你可以这样写
假设你的方法有签名:
int CTask::ThreeParameterTask(int par1, int par2, int par3)
要创build一个函数对象来绑定三个参数,你可以这样做
// 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; };
而且,使用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); }
在这里我们如何调用它
F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3( &CTask::ThreeParameterTask), task1,2122,23 );
注意:f3(); 将调用方法task1-> ThreeParameterTask(21,22,23);
更多血淋淋的细节 – > http://www.codeproject.com/Articles/26078/AC-Plug-in-ThreadPool-Design
std :: function和std :: bind的主要用途之一就是安全的函数指针。 网上有大量的文章解释了函数指针在C / C ++中的用处。 例如,它们对于实现callback机制很有用。 也就是说,你有一些函数需要很长时间才能执行,但是你不想等待它的返回,那么你可以在单独的线程上运行这个函数,并给它一个函数指针,它会在完成后callback。
这是一个如何使用这个示例代码:
class MyClass { private: //just shorthand to avoid long typing typedef std::function<void (float result)> CallbackType; //this function takes long time void longRunningFunction(CallbackType 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); } };