You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

提问

  1. 是否有符合需求的可行解决方案?
  2. 使用std::any能否优化实现?
  3. 能否为这个类提供更合适的命名建议?

解决方案

核心思路:用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;
};

实现说明

  1. 类型安全:std::any_cast会在类型不匹配时抛出异常,捕获后返回默认指针,避免未定义行为,同时无需调用者显式转换。
  2. 接口匹配需求:完全贴合期望接口,insert按名称关联对象指针,find通过传入的默认指针自动推导目标类型。
  3. 灵活性:模板参数支持自定义键类型和底层字典容器(比如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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:10:15