Where in the gcc source std :: bind copies the arguments to the data structure?

In an attempt to understand the conditions under which std::bind allocates memory, I looked at this answer , which gives some intuition, but I wanted to get a more detailed understanding, so I went and looked at the source for gcc .

I am studying the following source code for std::bind from the gcc implementation of the C ++ standard library.

  /** * @brief Function template for std::bind. * @ingroup binders */ 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)...); } 

For function F and parameters A and B, where can I find the code that copies them into the returned data structure, or is this compiler generated?

+6
source share
2 answers

This line:

 __result_type(__maybe_type::__do_wrap(std::forward<_Func>(__f)), std::forward<_BoundArgs>(__args)...); 

Parameters, both called (wrapped with __do_wrap ) and arguments, are redirected to the __result_type type, which stores them in the data structure.

You should look for the __result_type code, it wraps the data returned first in the specific implementation type, the above two lines (this is _Bind_helper<false, _Func, _BoundArgs...>::type ).
The actual type is _Bind (search for class _Bind ), which has a constructor that accepts both called and arguments and, of course, is a template class (exposed using several helpers).
In fact, Bind_helper<whatever>::type (i.e. the return type) is defined as typedef _Bind<whatever> type , you can search for this class and thatโ€™s it.

+1
source

Nowhere do we allocate memory. We just create an object with a type specific to that particular bind() that has a member of the function (possibly wrapped in some other type and copied / moved as needed) and tuple arguments (copied / moved as needed).

The standard does not say anything about memory allocation, but there is no need to do such a thing for bind() , so any good implementation will not.


This overload returns a:

 _Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type 

This overload only participates in overload resolution if __is_socketlike<_Func>::value is false . In this case, this type:

 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; 

Ignoring the value of the template argument, we basically build something like:

 template<typename _Signature> struct _Bind; template<typename _Functor, typename... _Bound_args> class _Bind<_Functor(_Bound_args...)> : public _Weak_result_type<_Functor> { ... }; 

which has the following elements:

 _Functor _M_f; tuple<_Bound_args...> _M_bound_args; 

and related constructors:

  template<typename... _Args> explicit _Bind(const _Functor& __f, _Args&&... __args) : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...) { } template<typename... _Args> explicit _Bind(_Functor&& __f, _Args&&... __args) : _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...) { } 
+1
source

All Articles