我知道什么算子是什么以及何时使用std
算法,但我还没有理解Stroustrup在C++11 FAQ中对它们的看法。
任何人都可以解释什么std::bind
和std::function
,什么时候应该使用,并给新手一些例子?
std::bind
是为partial function application。
也就是说,假设你有一个函数对象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
(它使用<=
操作符而不是<
,所以如果它们不一致那么你可能需要这个,你可能还需要访问该类的作者cluestick)。不过,如果你正在使用一种功能性的编程风格,那就会出现这种转变。
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 :: 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);
}
};
我用了很长时间回来用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
};
现在,为了绑定参数,我们必须编写一个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;
};
并且,使用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/A-C-Plug-in-ThreadPool-Design