微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 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 技巧”来做到这一点:

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 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

,

只是总结一些其他很好的答案的评论......

成员别名通常仅命名为 type。最好避免使用宏 (Why are preprocessor macros evil and what are the alternatives?),为了减少调用者的冗长,您可以使用函数模板:

#include <iostream>
#include <typeinfo>

template<typename T>
struct TypeFromPtrToMember; // needs no definition

template<typename T,typename P>
struct TypeFromPtrToMember<P T::*>
{
    using type = T;
};

class SomeClass
{
public:
    int _int;
};

template <typename T>
void do_some_stuff(T t){
    std::cout << typeid(typename TypeFromPtrToMember<T>::type).hash_code();;
}

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

命名成员别名 typeso common,即使您需要两个特征,我也会这样做。另一个特征与 using type = P; 基本相同。

在上面,使用 trait 时仍然需要写 typename(因为 TypeFromPtrToMember<T>::typedependent name)。从 C++11 开始,我们可以使用 template alias 来帮助解决这个问题。模板别名不能部分特化,但我们已经有了这个特性,只需要转发给它:

template <typename T>
using TypeFromPtrToMember_t = typename TypeFromPtrToMember<T>::type;

这样 do_some_stuff 可以是:

template <typename T>
void do_some_stuff(T t){
    std::cout << typeid(TypeFromPtrToMember_t<T>).hash_code();;
}

我希望您同意现在不再需要宏。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?