你可以用“template技巧”做到这一点:
template<typename T>
struct PointerToMemberDecomposer {};
template<typename T, typename P>
struct PointerToMemberDecomposer<P T::*>
{
using ClassType = T;
using MemberType = P;
};
并将您的代码更改为:
#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)
}
定义几个模板化别名可以让代码更简洁:
#define GET_POINTER_TO_MEMBER_CLASS_TYPE(ptr) PointerToMemberDecomposer<decltype(ptr)>::ClassType
#define GET_POINTER_TO_MEMBER_MEMBER_TYPE(ptr) PointerToMemberDecomposer<decltype(ptr)>::MemberType
因此您可以将DO_SOME_STUFF 更改为:
#define DO_SOME_STUFF(ptr) std::cout << typeid(GET_POINTER_TO_MEMBER_MEMBER_TYPE(ptr)).hash_code();
说明
这种技术称为Partial template specialization。
PointerToMemberDecomposer 的第二个定义将在 pointer-to-member 类型作为模板参数传递时使用;并将捕获新的T 和P typenames。使用那些新的typenames;它将定义两个类型别名(ClassType 和 MemberType),因此 T 和 P 可以在 PointerToMemberDecomposer 结构之外使用。
使用PointerToMemberDecomposer时;您应该使用decltype 运算符,其作用类似于Python 中的type 或C# 中的typeof。 decltype(x) 传递 x 的类型,而不是 x 本身。
更新
正如463035818_is_not_a_number 所提到的;宏可以替换为templated aliases
template <typename T>
using ClassTypeFromPtrToMember_t = typename PointerToMemberDecomposer<T>::ClassType;
template <typename T>
using MemberTypeFromPtrToMember_t = typename PointerToMemberDecomposer<T>::MemberType;
但是您仍然应该使用decltype,而DO_SOME_STUFF 是宏而不是模板函数,我们不能直接访问ptr 的类型(请参阅463035818_is_not_a_number's answer 以获取DO_SOME_STUFF 的模板函数版本):
#define DO_SOME_STUFF(ptr) std::cout << typeid(MemberTypeFromPtrToMember_t<decltype(ptr)>).hash_code();
在这种情况下; DO_SOME_STUFF 可以转换为模板函数。但是您可能希望例如用宏参数填充非捕获 lambda;这要求 DO_SOME_STUFF 是一个宏。
此外,您可能希望将ClassType 和MemberType 更改为type 并创建两个单独的structs(或classes)来检索这些类型别名;如果你想让PointerToMemberDecomposer 看起来像 C++ 的标准库。
更多详情;见463035818_is_not_a_number's answer