先看如下代码:
double my_divide (double x, double y) {return x/y;}
class A {
public:
void fun_3(int k,int m) {
std::cout << "print: k = "<< k << ", m = " << m << std::endl;
}
};
int main()
{
A a;
//f5的类型为 function<void(int, int)>
auto f5 = std::bind(&A::fun_3, &a, std::placeholders::_1, std::placeholders::_2); //使用auto关键字
f5(10, 20); //调用a.fun_3(10,20),print: k=10,m=20
function<void(int, int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
fc(10, 20);
auto fn_half = std::bind (my_divide,std::placeholders::_1,2);
cout<<fn_half(4)<<endl;
auto fn_half1 = std::bind (&my_divide,std::placeholders::_1,2);
cout<<fn_half1(4)<<endl;
return 0;
}
对于&a和a都是可以正确编译执行,结果正确,往常我总是用&a的写法,传的是指针进去,所以见到绑定成员函数,第二个参数传的是a,本身对象而感到困惑
查阅资料得出:
这个是bind关于绑定成员函数的源码
template<typename _Result, typename _Func, typename... _BoundArgs>
struct _Bindres_helper
: _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>
{
typedef typename decay<_Func>::type __functor_type;
typedef _Bind_result<_Result,
__functor_type(typename decay<_BoundArgs>::type...)>
type;
};
template<typename _Result, typename _Func, typename... _BoundArgs>
inline
typename _Bindres_helper<_Result, _Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)
{
typedef _Bindres_helper<_Result, _Func, _BoundArgs...> __helper_type;
return typename __helper_type::type(std::forward<_Func>(__f),
std::forward<_BoundArgs>(__args)...);
}
在这个模板函数中,_Bindres_helper
类模板用于根据 _Func
和 _BoundArgs
推导绑定结果的类型。它还使用 typename decay<_Func>::type
去除 _Func
的引用和修饰符,以便获得准确的函数类型。然后它返回创建的绑定对象的实例。
综上所述,当调用 std::bind
绑定成员函数时,需要传入成员函数的指针(或可调用对象)、成员函数所属的对象(或指向该对象的指针)、以及任何要为成员函数提供的参数。通过源码中的模板函数重载选择正确的实现,并返回创建的绑定对象。
bind(_Func&& __f, _BoundArgs&&... __args)
怎么做到绑定成员函数指针,和对象或对象指针的,,还有临时变量,右值等等
是因为用到了&&右值引用和引用折叠
- 对于
_Func&& __f
这个参数,如果传递给std::bind
的是一个右值,那么_Func
将会被推导为该右值的类型,同时右值引用保持原样,因此可以接收对象的右值引用。 - 如果传递给
std::bind
的是一个左值,根据引用折叠规则,_Func
将被推导为左值的引用类型,即_Func&
。这意味着它可以接收对象的左值引用。
同样地,在 _BoundArgs&&... __args
这个参数中,根据引用折叠规则,如果传递给 std::bind
的是右值,那么 _BoundArgs
和 __args
将会被推导为右值引用类型,并保持原样。这意味着它们可以接收对象的右值引用列表。如果传递给 std::bind
的是左值,那么它们将被推导为左值引用类型,即 _BoundArgs&
和 __args&
。这意味着它们可以接收对象的左值引用列表。
综上所述,通过引用折叠规则和模板推导,std::bind
函数的参数可以接收对象和对象的指针(作为左值引用)
但是但是!虽然
auto boundFunc = std::bind(&MyClass::printMessage, obj, "Hello, world!");
,虽然参数传递了一个对象 obj
(而不是对象的指针或引用),但这个代码仍然能够编译和运行,并且没有出现错误。这是因为 std::bind
函数可以自动推断对象 obj
的正确类型。std::bind
函数使用了完美转发(perfect forwarding)来处理参数,因此它能够处理对象按值传递的情况。
std::bind
函数在内部会对对象 obj
进行一次拷贝,以便将其绑定到成员函数 MyClass::printMessage
。但是,请注意,如果对象很大或者具有复杂的拷贝语义,就需要谨慎使用这种方式。
为了确保代码的健壮性和可维护性,建议在使用 std::bind
时,仍然传递指向对象的指针或引用作为 std::bind
的参数。这样可以更清晰地表达意图,并避免潜在的拷贝开销或对象生命周期问题。所以,下面的代码更推荐:
传指针的方式:
MyClass obj;
auto boundFunc = std::bind(&MyClass::printMessage, &obj, "Hello, world!");
传引用的方式:
MyClass obj;
auto boundFunc = std::bind(&MyClass::printMessage, std::ref(obj), "Hello, world!");
建议阅读:
【C++】C++11的std::function和std::bind用法详解_Yngz_Miao的博客-CSDN博客
C++ STL初识:bind封装函数讲解 - hugeYlh - 博客园 (cnblogs.com)文章来源:https://www.toymoban.com/news/detail-617788.html
C++11新特性——std::bind参数绑定_山河君的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-617788.html
到了这里,关于有关bind一些困惑解答的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!