C++17实现按名称关联任意类型指针的字典技术求助
问题描述
希望在C++17中实现一个字典,能够将名称与任意数量类型的指针关联,查找时无需调用者显式转换即可推导类型,且这些类型无法提前通过可变模板指定。
期望接口
AnyDict<std::string, std::map> dict; float num = 0.5f; std::string str = {"Value"}; // 若两次插入均成功则为true if ( dict.insert("Hello"s, num) && dict.insert("Other"s, str) ) ; // ... // 应返回true dict.remove("Hello"s); std::string def = {""}; // 应返回指向"Other"的指针,失败则返回指向def的指针 auto* value = dict.find("Other"s, &def);
当前实现方案及问题
目前的实现分为两部分,但只能按类型索引,不符合按名称索引的需求:
1. 类型转编号
// Currently I'm not using dlls or anything, but... class TypeIdx { public: template <class Type> static int get() { // ugly. static const int s_idx = s_count++; return s_idx; } private: static inline int s_count = 0; };
2. 字典包装类
template <template <class, class> class Dict> class AnyDict { public: // constructors, destructor, etc. template <class Type> bool insert(Type& item) { int key = TypeIdx::get<Type>(); // The delegate must return true on success // or false on failure. return m_dict.insert(key, (void*) &item); } template <class Type> bool remove() { int key = TypeIdx::get<Type>(); // The delegate must return true on success // or false on failure. return m_dict.remove(key); } template <class Type> Type* find(Type* def) { int key = TypeIdx::get<Type>(); // The delegate must return a pointer to // the item found on success, or to "def" // on failure. return (Type*) m_dict.find(key, def); } private: // Here the void* lets me save a pointer to // anything but i can't deduce back the type. Dict<int, void*> m_dict; };
提问
- 是否有符合需求的可行解决方案?
- 使用
std::any能否优化实现? - 能否为这个类提供更合适的命名建议?
解决方案
核心思路:用std::any存储类型信息
你的核心需求是按名称索引,同时保留类型安全的指针访问,之前的方案用void*丢失了类型信息,而C++17的std::any正好可以存储任意类型的对象(包括指针),同时保留类型元信息,完美解决这个问题。
完整实现
#include <any> #include <map> #include <string> #include <stdexcept> template <typename Key, template <typename...> class Dict = std::map> class TypedNamedDict { public: // 插入:将名称与对象指针关联,返回是否插入成功(键不存在则成功) template <typename T> bool insert(const Key& key, T& item) { if (m_dict.count(key)) { return false; } m_dict.emplace(key, std::addressof(item)); return true; } // 删除:根据名称移除条目,返回是否删除成功(键存在则成功) bool remove(const Key& key) { return m_dict.erase(key) > 0; } // 查找:根据名称查找,若类型匹配则返回指针,否则返回默认指针 template <typename T> T* find(const Key& key, T* default_ptr) { auto it = m_dict.find(key); if (it == m_dict.end()) { return default_ptr; } try { return std::any_cast<T*>(it->second); } catch (const std::bad_any_cast&) { return default_ptr; } } private: Dict<Key, std::any> m_dict; };
实现说明
- 类型安全:
std::any_cast会在类型不匹配时抛出异常,捕获后返回默认指针,避免未定义行为,同时无需调用者显式转换。 - 接口匹配需求:完全贴合期望接口,
insert按名称关联对象指针,find通过传入的默认指针自动推导目标类型。 - 灵活性:模板参数支持自定义键类型和底层字典容器(比如
std::unordered_map)。
std::any的优势
相比之前的void*方案,std::any的优势在于:
- 保留类型元信息,消除裸指针的类型不安全转换
- 无需手动维护类型编号(
TypeIdx类可完全移除) - 异常机制提供清晰的类型不匹配处理路径
命名建议
TypedNamedDict:突出“按名称索引+类型安全”的核心特性NamedAnyPointerDict:直白表达“存储任意类型指针的命名字典”TypeSafeNamedPointerMap:强调类型安全与命名索引的特性
测试示例
#include <iostream> int main() { TypedNamedDict<std::string> dict; float num = 0.5f; std::string str = "Value"; if (dict.insert("Hello", num) && dict.insert("Other", str)) { std::cout << "插入成功" << std::endl; } std::cout << "删除Hello:" << (dict.remove("Hello") ? "成功" : "失败") << std::endl; std::string def = ""; auto* value = dict.find("Other", &def); std::cout << "查找Other的值:" << *value << std::endl; // 类型不匹配的情况,返回默认指针 float float_def = 0.0f; auto* wrong_type = dict.find("Other", &float_def); std::cout << "类型不匹配时返回默认值:" << *wrong_type << std::endl; return 0; }
内容的提问来源于stack exchange,提问作者Giovanni
相关产品推荐
相关产品推荐

