Std::function和Std::bind是什么,什么时候应该使用它们
std::function and std::bind: what are they, and when should they be used?
我知道函子是什么,以及什么时候在std
算法中使用它们,但我还不明白Stroustrup在c++ 11 FAQ中是怎么说的。
谁能解释一下std::bind
和std::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
- Confusion: decltype vs std::function
- 为什么 std::function 可以作为 std::not2 的参数?
- 'max'匹配'std::function<const int &(const int &, const int &)>'无过载
- 传递给std::function template的template参数究竟代表什么
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 将函数包装器转换为 std::function
- 类型擦除的std::function与虚拟函数调用的开销
- C++ std::function 对于类 exept 的所有实例都是空的(只有 Visual2019 编译器问题)
- 如果模板没有可变参数,则 Lambda 被推导出为 std::function
- 将 lambda 表达式传递给 std::function in C++
- 模板类的部分模板专用化,如 std::function
- 可变参数模板参数扩展 类型为 std::function 的类成员
- 从 std::function in C++ 访问模板化 lambda
- 什么是 std::function::argument_type 的替代品?
- C++派生类重载函数(带有 std::function 参数)不可见
- 如何在 qi 符号表中使用 std::function
- 将 std::function 与模板一起使用
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数
- 我需要在 std::function 上使用 unique_ptr 吗?
- 如何将函数指针从 std::function 传递到 Linux 克隆?