如何实现方法获取对象的typedef别名字符串而非原始类型名?
实现获取typedef别名的方案
C++中typedef只是编译期的类型别名,编译完成后会被完全替换为原始类型,因此仅靠typeid无法直接获取别名——运行时类型系统中不存在别名的记录。要实现需求,必须在编译期通过模板机制手动关联类型与别名,以下是两种符合低侵入性要求的方案:
方案1:手动模板特化(完全非侵入)
无需修改原有typedef定义,仅需在统一位置为需要识别的typedef编写模板特化,维护类型到别名的映射:
#include <typeinfo> #include <string> #include <memory> #include <cstdlib> // 辅助函数:解混淆编译器生成的类型名 std::string demangle(const char* name) { int status = 0; std::unique_ptr<char, void(*)(void*)> res { abi::__cxa_demangle(name, nullptr, nullptr, &status), std::free }; return (status == 0) ? res.get() : name; } // 基础模板:默认返回原始类型的解混淆名称 template<typename T> struct TypeName { static std::string get() { return demangle(typeid(T).name()); } }; // 针对每个typedef编写特化,关联类型与别名 typedef int my_int; template<> struct TypeName<my_int> { static std::string get() { return "my_int"; } }; typedef std::map<std::string, std::vector<int>> StringIntVecMap; template<> struct TypeName<StringIntVecMap> { static std::string get() { return "StringIntVecMap"; } }; // 对外接口函数 template<typename T> std::string typedef_type(const T&) { return TypeName<T>::get(); } // 测试示例 #include <iostream> #include <map> #include <vector> int main() { my_int i; std::cout << typedef_type(i) << "\n"; // 输出: my_int StringIntVecMap m; std::cout << typedef_type(m) << "\n"; // 输出: StringIntVecMap int raw_int; std::cout << typedef_type(raw_int) << "\n"; // 输出: int return 0; }
优缺点:
- 完全不修改原有代码,侵入性为0;
- 缺点是需要手动为每个typedef编写特化,若typedef数量极多,维护成本较高。
方案2:宏封装typedef(低侵入)
通过宏替换原有typedef定义,自动生成模板特化,无需手动维护映射:
#include <typeinfo> #include <string> #include <memory> #include <cstdlib> std::string demangle(const char* name) { int status = 0; std::unique_ptr<char, void(*)(void*)> res { abi::__cxa_demangle(name, nullptr, nullptr, &status), std::free }; return (status == 0) ? res.get() : name; } template<typename T> struct TypeName { static std::string get() { return demangle(typeid(T).name()); } }; // 封装typedef的宏,自动生成类型别名与对应的模板特化 #define TYPEDEF(ORIG_TYPE, ALIAS) \ typedef ORIG_TYPE ALIAS; \ template<> \ struct TypeName<ALIAS> { \ static std::string get() { return #ALIAS; } \ }; // 使用宏定义typedef(替换原有typedef即可) TYPEDEF(int, my_int); TYPEDEF(std::map<std::string, std::vector<int>>, StringIntVecMap); template<typename T> std::string typedef_type(const T&) { return TypeName<T>::get(); } // 测试示例 #include <iostream> #include <map> #include <vector> int main() { my_int i; std::cout << typedef_type(i) << "\n"; // 输出: my_int StringIntVecMap m; std::cout << typedef_type(m) << "\n"; // 输出: StringIntVecMap return 0; }
优缺点:
- 仅需将原有
typedef替换为宏调用,侵入性极低; - 自动维护类型与别名的关联,无需手动编写特化,适合大量typedef的场景;
- 若代码中typedef分散在多个文件,只需将宏定义放在公共头文件中即可。
注意事项
- 若同一原始类型存在多个typedef别名(如
typedef int A; typedef int B;),由于模板特化基于类型本身,无法区分不同别名——此时需改用包装类而非直接typedef(侵入性会提高),但这种场景在语义化命名的实践中较少见; - 上述代码依赖GCC/Clang的
abi::__cxa_demangle函数,若使用MSVC,需替换为对应的解混淆函数(如UnDecorateSymbolName)。
内容的提问来源于stack exchange,提问作者sancho.s ReinstateMonicaCellio
相关产品推荐
相关产品推荐

