1, 小特性
demo1:
#include <iostream>
#include <functional>
void function(int& number)
{
number = 50;
}
using functionType = void(*)(int&);
int main()
{
//case 1:
int n1 = 10;
auto f1 = std::bind(function, 10);
f1();
std::cout<<n1<<std::endl; //输出: 10.
//case 2:
int n2 = 20;
auto f2 = std::bind(function, std::ref(n2));
f2();
std::cout<<n2<<std::endl; //输出: 50.
//case 3:
int n3 = 30;
auto f3 = std::bind(function, n3);
f3();
std::cout<< n3 <<std::endl; //输出: 30
return 0;
}
2, std::bind的实现(debian GCC6.3)
由于标准没用要求std::bind的具体实现只是要求了std::bind的具体功能.我这里只有linux. vs就不考虑了.下面让我们一点一点往下看.
code block 1: std::bind
template<typename _Func, typename... _BoundArgs>
inline typename
_Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)
{
typedef _Bind_helper<false, _Func, _BoundArgs...> __helper_type;
typedef typename __helper_type::__maybe_type __maybe_type;
typedef typename __helper_type::type __result_type;
return __result_type(__maybe_type::__do_wrap(std::forward<_Func>(__f)),
std::forward<_BoundArgs>(__args)...);
}
1), 首先我们看到 std::bind(__Func&& f, _BoundArgs&&... __args).
2), 虽然f的类型为: __Func&&但是仍然是可以传递一个指向class/struct member function/data的指针.
3), 我们看到std::bind依赖 _Bind_helper(struct)以及 __is_socketlike(struct).
code block 2: __is_socketlike
template<typename _Tp, typename _Tp2 = typename decay<_Tp>::type>
using __is_socketlike = __or_<is_integral<_Tp2>, is_enum<_Tp2>>;
1) __is_socketlike依赖 __or_(struct), 同时接受一个2个template argument:
_Tp 和 _Tp2, 但是__or_(struct)并不依赖_Tp, 而是是需要获取 std::decay<_Tp>::type得到的_Tp2.
code block 3: __or_ 和 conditional
template<typename...>
struct __or_; //struct template declare
template<>
struct __or_<>
: public false_type
{ }; //specialized
template<typename _B1>
struct __or_<_B1>
: public _B1
{ }; //specialized
template<typename _B1, typename _B2>
struct __or_<_B1, _B2>
: public conditional<_B1::value, _B1, _B2>::type
{ }; //specialized
template<typename _B1, typename _B2, typename _B3, typename... _Bn>
struct __or_<_B1, _B2, _B3, _Bn...>
: public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type
{ }; //specialized
template<bool _Cond, typename _Iftrue, typename _Iffalse>
struct conditional
{ typedef _Iftrue type; }; // struct template declare
template<typename _Iftrue, typename _Iffalse>
struct conditional<false, _Iftrue, _Iffalse>
{ typedef _Iffalse type; }; // specialized
1), 首先看 conditional(struct):
1, 当 _Cond为true的时候, conditional的类型为 _Iftrue
2, 当_Cond为false的时候, conditional的类型为 _Iffalse
2), __or_(struct)可以接受 可变的template arguments, 但是需要注意的是我们提供的 template arguments必须是可以 operator bool 且必须具有一个 member data value 且value必须是bool类型.
code block 4: _Bind_helper
template<bool _SocketLike, typename _Func, typename... _BoundArgs>
struct _Bind_helper
: _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>
{
typedef _Maybe_wrap_member_pointer<typename decay<_Func>::type>
__maybe_type;
typedef typename __maybe_type::type __func_type;
typedef _Bind<__func_type(typename decay<_BoundArgs>::type...)> type;
}; //struct template declare
template<typename _Func, typename... _BoundArgs>
struct _Bind_helper<true, _Func, _BoundArgs...>
{ }; //specialized
1),如果 _Sokectlike的值为true, 就表明 _Func的类型为 integer/enum, 这个时候是不能作为函数调用的因此错误.
2), _Bind_helper依赖 _Bind_check_arity(struct), _Maybe_wrap_member_pointer(struct) 以及 _Bind(struct).
code block 5: _Bind_check_arity
template<typename _Func, typename... _BoundArgs>
struct _Bind_check_arity { };
template<typename _Ret, typename... _Args, typename... _BoundArgs>
struct _Bind_check_arity<_Ret (*)(_Args...), _BoundArgs...>
{
static_assert(sizeof...(_BoundArgs) == sizeof...(_Args),
"Wrong number of arguments for function");
};
template<typename _Ret, typename... _Args, typename... _BoundArgs>
struct _Bind_check_arity<_Ret (*)(_Args......), _BoundArgs...>
{
static_assert(sizeof...(_BoundArgs) >= sizeof...(_Args),
"Wrong number of arguments for function");
};
template<typename _Tp, typename _Class, typename... _BoundArgs>
struct _Bind_check_arity<_Tp _Class::*, _BoundArgs...>
{
using _Arity = typename _Mem_fn<_Tp _Class::*>::_Arity;
using _Varargs = typename _Mem_fn<_Tp _Class::*>::_Varargs;
static_assert(_Varargs::value
? sizeof...(_BoundArgs) >= _Arity::value + 1
: sizeof...(_BoundArgs) == _Arity::value + 1,
"Wrong number of arguments for pointer-to-member");
};