c++ - 如何在 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)。

最佳答案

你可以用“template trick”来做到这一点:

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();

解释

这种技术称为部分模板特化PointerToMemberDecomposer 的第二个定义将在 pointer-to-member 类型作为模板参数传递时使用;并将捕获新的 TP typename。使用那些新的 typename;它将定义两个类型别名(ClassTypeMemberType),因此 TP 可以在 PointerToMemberDecomposer 结构。

当使用PointerToMemberDecomposer时;你应该使用 decltype运算符,其作用类似于 Python 中的 type 或 C# 中的 typeofdecltype(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;

但是你仍然应该使用 decltypeDO_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 是一个宏。

此外,您可能希望将 ClassTypeMemberType 更改为 type 并创建两个单独的 struct(或 classes) 用于检索那些类型别名;如果您希望 PointerToMemberDecomposer 看起来像 C++ 的标准库。

了解更多详情;见463035818_is_not_a_number's answer

https://stackoverflow.com/questions/68252606/

相关文章:

php - Laravel Sail 部署就绪了吗

bash - 如何从我的 bash 脚本创建日志文件

sql - 在雪花中查询数组的子集

java - 将小写的短工作日解析为 Java 8 的时间 DayOfWeek

c++ - 什么是 std::vector vec{3};实际上呢?

c++ - 为 const 引用和右值引用编写重载

typescript - 安全地消除 typescript 中的无效性

r - 从 R 中的其他数据帧更新列中的某些值

swift - 如何在 swift ui 的导航 View 中的大标题下方添加副标题?

android-studio - 无法加载 com.github.smarteist.autoima