You can do that with a "template
trick":
template<typename T>
struct PointerToMemberDecomposer {};
template<typename T, typename P>
struct PointerToMemberDecomposer<P T::*>
{
using ClassType = T;
using MemberType = P;
};
And change your code to:
#include <iostream>
template<typename T>
struct PointerToMemberDecomposer {};
template<typename T, typename P>
struct PointerToMemberDecomposer<P T::*>
{
using ClassType = T;
using MemberType = P;
};
class SomeClass
{
public:
int _int;
};
#define DO_SOME_STUFF(ptr) std::cout << typeid(PointerToMemberDecomposer<decltype(ptr)>::MemberType).hash_code();
int main()
{
int SomeClass::* ptr_to_int_member = &SomeClass::_int;
DO_SOME_STUFF(ptr_to_int_member)
}
Defining a couple of templated aliases can make the code a little bit cleaner:
#define GET_POINTER_TO_MEMBER_CLASS_TYPE(ptr) PointerToMemberDecomposer<decltype(ptr)>::ClassType
#define GET_POINTER_TO_MEMBER_MEMBER_TYPE(ptr) PointerToMemberDecomposer<decltype(ptr)>::MemberType
So you can change DO_SOME_STUFF
to:
#define DO_SOME_STUFF(ptr) std::cout << typeid(GET_POINTER_TO_MEMBER_MEMBER_TYPE(ptr)).hash_code();
Explanation
This technique is called Partial template specialization
.
The second definition of PointerToMemberDecomposer
will be used when a pointer-to-member
type is passed as template argument; And will catch new T
and P
typename
s. using those new typename
s; It will define two type aliases (ClassType
and MemberType
) so T
and P
can be used outside of the PointerToMemberDecomposer
struct.
When using PointerToMemberDecomposer
; you should use decltype operator which acts like type
in Python or typeof
in C#. decltype(x)
passes the type of x
instead of x
itself.
Update
As 463035818_is_not_a_number
have mentioned; macros can be replaced with templated aliases
template <typename T>
using ClassTypeFromPtrToMember_t = typename PointerToMemberDecomposer<T>::ClassType;
template <typename T>
using MemberTypeFromPtrToMember_t = typename PointerToMemberDecomposer<T>::MemberType;
But you should still use decltype
while DO_SOME_STUFF
is a macro instead of a templated function and we cant access ptr
's type directly (see 463035818_is_not_a_number's answer for templated function version of DO_SOME_STUFF
):
#define DO_SOME_STUFF(ptr) std::cout << typeid(MemberTypeFromPtrToMember_t<decltype(ptr)>).hash_code();
In this case; DO_SOME_STUFF
can be converted to a templated function. But you might want to for example fill a non capturing lambda with macro arguments; which requires DO_SOME_STUFF
to be a macro.
Also, you might want to change ClassType
and MemberType
to type
and create two separated struct
s (or class
es) for retrieving those type aliases; If you want PointerToMemberDecomposer
to look like C++'s standard library.
For more details; see 463035818_is_not_a_number's answer