如何在编译时实现类成员与编号的映射并返回对应成员?
编译时实现编号到类成员的映射并返回对应成员
我想构建一个编译时映射,把编号和类的成员关联起来,然后通过函数在编译时返回类的对应成员。
现有代码
class MyClass { public: float MemberA; std::uint32_t MemberB; }; int ProcessMember(int iMemberID, MyClass* pClass) { if (iMemberID == 1){ ProcessMember(pClass->MemberA); } else if (iMemberID == 2){ ProcessMember(pClass->MemberB); } }
期望实现的逻辑
希望能让函数接收编译时参数来指向MyClass的指定成员,类似如下逻辑:
template <class T> void Multiply(T& CurrentValue) { CurrentValue = CurrentValue * 2; } int ProcessMember(int iMemberID, MyClass* pClass) { if (iMemberID == 1){ Multiply(func(1)); } else if (iMemberID == 2){ Multiply(func(2)); } }
我之前尝试过下面的代码,但它必须在调用前提前指定T才能编译通过:
template <typename T> T& GetValueFromValueName(int MemberID, MyClass* pClass) { switch (MemberID) { case 1: return pClass->MemberA; case 2: return pClass->MemberB; } }
请问这种编译时映射的实现是否可行?
解决方案
核心思路:编译时非类型参数+成员指针绑定
要实现编译时关联编号与成员,需利用C++的模板非类型参数和类成员指针,将成员信息固化在编译期。同时因为ProcessMember接收的是运行时传入的iMemberID,需要在运行时分支中调用编译时确定的成员访问逻辑。
具体实现代码
1. 定义编译时成员映射模板
通过模板特化,将编号与对应成员的类型、指针绑定:
#include <cstdint> class MyClass { public: float MemberA; std::uint32_t MemberB; }; // 基础模板 template<int ID> struct MemberMap; // 编号1对应MemberA template<> struct MemberMap<1> { using Type = float; static constexpr Type MyClass::* ptr = &MyClass::MemberA; }; // 编号2对应MemberB template<> struct MemberMap<2> { using Type = std::uint32_t; static constexpr Type MyClass::* ptr = &MyClass::MemberB; };
2. 编译时获取成员的函数
基于映射模板,编写模板函数返回指定成员的引用:
template<int ID> typename MemberMap<ID>::Type& get_member(MyClass& obj) { return obj.*MemberMap<ID>::ptr; }
3. 适配运行时ID的调用逻辑
在运行时分支中,调用对应编译时版本的get_member:
template <class T> void Multiply(T& CurrentValue) { CurrentValue = CurrentValue * 2; } int ProcessMember(int iMemberID, MyClass* pClass) { if (!pClass) return -1; // 空指针检查 switch(iMemberID) { case 1: Multiply(get_member<1>(*pClass)); break; case 2: Multiply(get_member<2>(*pClass)); break; default: // 处理无效编号 return -1; } return 0; }
方案优势
- 所有成员映射逻辑在编译期完成,无运行时额外开销;
get_member<ID>返回的引用类型与成员完全匹配,调用Multiply时会自动推导模板参数,无需手动指定;- 运行时分发仅做简单分支跳转,兼顾运行时ID需求与编译时类型安全。
扩展优化:用std::tuple简化多成员映射
如果类成员数量较多,可借助std::tuple存储成员指针,结合编译时索引简化映射:
#include <tuple> // 存储所有成员指针的tuple constexpr auto MyClassMembers = std::make_tuple( &MyClass::MemberA, &MyClass::MemberB ); // 基于索引获取成员 template<std::size_t Index> auto& get_member(MyClass& obj) { return obj.*std::get<Index>(MyClassMembers); } // 调用时编号对应索引(编号1→索引0,编号2→索引1) int ProcessMember(int iMemberID, MyClass* pClass) { if (!pClass) return -1; switch(iMemberID) { case 1: Multiply(get_member<0>(*pClass)); break; case 2: Multiply(get_member<1>(*pClass)); break; default: return -1; } return 0; }
内容的提问来源于stack exchange,提问作者NormakLOE32
相关产品推荐
相关产品推荐

