Reputation: 487
I am referring to a possible implementation of std::is_member_function_pointer
here.
template< class T >
struct is_member_function_pointer_helper : std::false_type {};
template< class T, class U>
struct is_member_function_pointer_helper<T U::*> : std::is_function<T> {};
template< class T >
struct is_member_function_pointer : is_member_function_pointer_helper< std::remove_cv_t<T> >
#include <type_traits>
class A {
public:
void member() { }
};
int main()
{
// fails at compile time if A::member is a data member and not a function
static_assert(std::is_member_function_pointer<decltype(&A::member)>::value,
"A::member is not a member function.");
}
I know that
"dectype(&A::member)"
will be
"void (A::*)()"
But I dont understand what type T and type U map to in "void (A::*)()"?
Upvotes: 3
Views: 387
Reputation: 21576
template< class T, class U>
struct is_member_function_pointer_helper<T U::*> : std::is_function<T> {};
The above specialization will be a match if it were possible to decompose the the primary template argument into a class type U
and a non-static member type T
. The class type U
is no longer useful here, because we've confirmed, its really a class.
The non-static member-type T
is then passed as the template argument to std::is_function
which has a whole lot of machinery in determining that T
is indeed a function.
But I dont understand what type
T
and typeU
map to invoid (A::*)()
?
As explained above, once we are able to decompose void (A::*)()
to match T U::*
You will find out that A::*
maps to U::*
. Lets remove that pattern, we are left with void ()
which is what T
will be.
Upvotes: 4
Reputation: 15918
I think it's easier to understand if we first translate the type-id into English. That is, void (A::*)()
is translated to "pointer to member of class A
of type function of () returning void
" and T U::*
to "pointer to member of class U
of type T
". Now if we compare the two type we can see U
corresponds to the class A
and T
corresponds to "function of () returning void
", i.e. void()
.
Upvotes: 2
Reputation: 7904
The pattern void (A::*)()
decomposes into T U::*
where U
is A
and T
is void ()
.
You can see the construction in inverse, like this:
struct A {};
using T = void ();
using U = A;
template <typename> struct print;
int main() {
print<T U::*>{};
// error: implicit instantiation of undefined template 'print<void (A::*)()>'
}
So the T
as void ()
is passed to std::is_function
which determines whether the given type is a function type.
In the case of pointer to data members, this fails because the deduced T
is going to be a non-function type.
Upvotes: 6