如何在C++中实现符合特定要求的异构映射(heterogeneous map)?
实现零开销异构映射(Heterogeneous Map)的方案探讨
需求概述
需要实现满足以下条件的异构映射special_map:
- 类型与读取键在运行时已知
- 几乎零开销,避免使用
boost::any这类性能较差的方案 - 不依赖冗长难用的宏
用户提供的关联代码示例:
class special_map; class buffer { public: ~buffer() = default; buffer(const special_map& map) : m_map(map) {}; template<typename T> void read(const std::string& name, T& value) { map.read<T>(name, value); return void(); } private: special_map m_map; };
问题解答
1. 能否使用void*结合reinterpret_cast?如何实现?是否安全?
可以用这种方式实现,但安全性需要严格约束:
实现思路
内部用std::unordered_map<std::string, std::pair<void*, std::type_index>>存储键值对:
void*指向实际数据的内存地址std::type_index记录数据的实际类型,用于读取时的类型校验- 提供模板化的插入接口存入数据,读取时先校验类型匹配,再通过
reinterpret_cast转换指针并赋值
示例代码
#include <unordered_map> #include <string> #include <typeindex> #include <stdexcept> class special_map { private: std::unordered_map<std::string, std::pair<void*, std::type_index>> m_data; public: // 插入数据:需保证数据生命周期长于special_map template<typename T> void insert(const std::string& name, const T& data) { m_data[name] = {const_cast<T*>(&data), std::type_index(typeid(T))}; } template<typename T> void read(const std::string& name, T& value) const { auto it = m_data.find(name); if (it == m_data.end()) { throw std::runtime_error("Key not found: " + name); } if (it->second.second != std::type_index(typeid(T))) { throw std::runtime_error("Type mismatch for key: " + name); } value = *reinterpret_cast<const T*>(it->second.first); } };
安全性分析
- 风险点:若存入的数据提前销毁,
void*会变成野指针,访问直接触发未定义行为;若绕过类型校验强制转换(比如存int读float),会导致类型错误。 - 安全前提:必须保证存入
special_map的数据生命周期不短于映射本身;读取时严格使用正确类型,依赖type_index校验避免类型不匹配。
2. 能否使用Boost.Hana或Boost.Fusion?
完全可以,这两个库都是针对编译期元编程设计,能实现类型安全且低开销的异构映射:
Boost.Hana方案
Boost.Hana的hana::map是编译期类型安全的异构映射,支持编译期常量键(比如字符串常量),性能零开销:
#include <boost/hana.hpp> #include <string> namespace hana = boost::hana; // 定义编译期键 constexpr auto key_name = hana::string_c<'n','a','m','e'>; constexpr auto key_age = hana::string_c<'a','g','e'>; // 构建异构map auto my_map = hana::make_map( hana::make_pair(key_name, std::string("Alice")), hana::make_pair(key_age, 30) ); // 读取数据 std::string name = hana::at_key(my_map, key_name); int age = hana::at_key(my_map, key_age);
如果需要运行时字符串键,可以结合hana::unpack做类型判断,开销远低于boost::any。
Boost.Fusion方案
Boost.Fusion的fusion::map同样是编译期异构映射,需要自定义键类型,类型安全且性能优异:
#include <boost/fusion/map.hpp> #include <boost/fusion/sequence.hpp> #include <string> namespace fusion = boost::fusion; // 定义键类型 struct name_key {}; struct age_key {}; // 构建异构map fusion::map< fusion::pair<name_key, std::string>, fusion::pair<age_key, int> > my_map( fusion::make_pair<name_key>("Bob"), fusion::make_pair<age_key>(25) ); // 读取数据 std::string name = fusion::at_key<name_key>(my_map); int age = fusion::at_key<age_key>(my_map);
内容的提问来源于stack exchange,提问作者Vero
相关产品推荐
相关产品推荐

