I have been looking at the source code for std::function
and std::bind
in gcc-4.7.2, and came across some syntax used for member function pointers which I don't understand.
What I don't understand is the specialisation of _Maybe_wrap_member_pointer
:
template<typename _Tp, typename _Class>
struct _Maybe_wrap_member_pointer<_Tp _Class::*> // note no comma here
Why is there no comma between _Tp
and _Class::*
?
Given member function void foo::bar()
(in my sample app below), what will _Tp
and _Class::*
resolve to here?
Below is my sample app which binds a member function pointer and object. (I have pulled out the source code relating to std::bind
specialisations/internals for member functions)
#include <iostream>
#include <functional>
template<typename T>
struct _Maybe_wrap_member_pointer;
template<typename _Tp, typename _Class>
struct _Maybe_wrap_member_pointer<_Tp _Class::*> // <-- I don't understand this
{ // why not <_Tp, _Class::*>
typedef std::_Mem_fn<_Tp _Class::*> type;
static type __do_wrap(_Tp _Class::* __pm)
{
return type(__pm);
}
};
template<typename _Func, typename... _BoundArgs>
struct _Bind_helper
{
typedef _Maybe_wrap_member_pointer<typename std::decay<_Func>::type> __maybe_type;
typedef typename __maybe_type::type __func_type;
typedef std::_Bind<__func_type(typename std::decay<_BoundArgs>::type...)> type;
};
template<typename _Func, typename... _BoundArgs>
inline
typename _Bind_helper<_Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)
{
typedef _Bind_helper<_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)...);
}
struct foo
{
void bar()
{
std::cout << __func__ << std::endl;
}
};
int main()
{
foo f;
std::function<void()> fun = bind(&foo::bar, f);
fun();
exit(0);
}
This is indeed the syntax used to specify member pointer types as template parameters.
Suppose you have a class
struct Bar
{
int n;
};
then a pointer to the member Bar::n
would have to have its type declared as int Bar::*
:
int Bar::* p = &Bar::n;
Note that int
refers to the type the pointer points to, and Bar::*
means "pointer to a member of Bar
".
Now the function of your example,
template<typename _Tp, typename _Class>
struct _Maybe_wrap_member_pointer<_Tp _Class::*> // note no comma here
accepts a template argument (just one!), which represents the member pointer type for a class _Class
, pointing to non-static data member of type _Tp
.
This is a template specialization of a class template that has only one template parameter:
template <typename T>
struct _Maybe_wrap_member_pointer
{ };
We can instantiate the specialization using the simple class above like this:
_Maybe_wrap_member_pointer<int Bar::*>
or using decltype
:
_Maybe_wrap_member_pointer<decltype(&Bar::n)>
In both cases, _Tp
is deduced to int
, and _Class
is deduced to Bar
.