Pregunta

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);
}
¿Fue útil?

Solución

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.

Otros consejos

  • Why is there no comma between _Tp and _Class::*?

jogojapan answered this part

  • Given member function void foo::bar() (in my sample app below), what will _Tp and _Class::* resolve to here?

A type such as Tp Class::* can represent a pointer to member data or a pointer to member function, in the latter case Tp will be a function type.

In your example _Tp will be the function type void () and _Class will be foo

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top