首页 > 解决方案 > 如何在 C++ 中分解指向成员的指针(获取类和成员类型)?

问题描述

我有这种情况:

#include <iostream>

class SomeClass
{
public:
    int _int;
};

#define DO_SOME_STUFF(ptr) std::cout << /* Print the typeid().hash_code() of the type which ptr is poiting to (int) */;

int main()
{
    int SomeClass::* ptr_to_int_member = &SomeClass::_int;
    DO_SOME_STUFF(ptr_to_int_member)
}

我想知道ptr指向的是哪种类型(当前是int)。知道哪个类拥有它int也很有用(目前是SomeClass)。

标签: c++pointerspointer-to-member

解决方案


你可以用一个“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并且会捕捉到新的TP typenames。使用那些新typename的;它将定义两个类型别名(ClassTypeMemberType),因此T可以PPointerToMemberDecomposer结构之外使用。

使用时PointerToMemberDecomposer;您应该使用在 Python 或C#中的decltype运算符。传递类型而不是自身。typetypeofdecltype(x)xx


更新

如前所述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;

但是您仍然应该使用decltypewhileDO_SOME_STUFF是宏而不是模板函数,并且我们无法ptr直接访问 的类型(请参阅463035818_is_not_a_number 的模板函数版本的答案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创建两个分隔的 s(或es)来检索这些类型别名;如果你想看起来像 C++ 的标准库。MemberTypetypestructclassPointerToMemberDecomposer

更多细节; 见463035818_is_not_a_number 的回答


推荐阅读