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

如何用pybind11实现C++动态类型Map的Python自动类型推导get方法?

用pybind11实现动态类型的Map.get方法

问题背景

我有一个C的Map类,可存储不同数据类型的条目。在C中,编译期无法确定条目的数据类型,因此必须使用模板访问器显式指定类型来获取值:

auto a = map.get<int>("my-int-entry");
auto b = map.get<std::string>("my-string-entry");

这个Map在运行时知晓每个条目的实际类型,因此希望在Python中调用a = map.get('my-int-entry')(返回int类型)、b = map.get('my-string-entry')(返回string类型)时,能自动根据运行时类型调用对应的C++模板方法get<int>或get<std::string>。

请问是否可直接通过pybind11实现该功能,还是需要编写纯Python函数来调用对应的C++映射函数?

解决方案

可以直接通过pybind11实现,无需额外编写纯Python包装函数。核心思路是在C++端新增一个非模板的重载get方法,让它根据运行时类型信息分发调用对应的模板get<T>,再通过pybind11将这个非模板方法暴露给Python。

具体实现步骤

  1. 给C++ Map类添加非模板的Python适配方法
    在Map类中新增一个get_py方法,该方法根据内部存储的类型信息(比如用std::type_index标记类型),分支调用对应类型的模板get<T>,并返回pybind11::object类型(pybind11可直接将其转换为Python对象)。示例代码如下:

    #include <pybind11/pybind11.h>
    #include <pybind11/stl.h>
    #include <typeindex>
    #include <unordered_map>
    #include <any>
    #include <stdexcept>
    
    class Map {
    private:
        std::unordered_map<std::string, std::any> data_store;
        std::unordered_map<std::string, std::type_index> type_records;
    public:
        // 模板set方法,存储值并记录类型
        template <typename T>
        void set(const std::string& key, T value) {
            data_store[key] = std::move(value);
            type_records[key] = std::type_index(typeid(T));
        }
    
        // 模板get方法,供C++内部调用
        template <typename T>
        T get(const std::string& key) const {
            return std::any_cast<T>(data_store.at(key));
        }
    
        // 非模板方法,供pybind11暴露给Python
        pybind11::object get_py(const std::string& key) const {
            auto type_iter = type_records.find(key);
            if (type_iter == type_records.end()) {
                throw std::out_of_range("Key not exists");
            }
            const auto& entry_type = type_iter->second;
    
            if (entry_type == std::type_index(typeid(int))) {
                return pybind11::cast(get<int>(key));
            } else if (entry_type == std::type_index(typeid(std::string))) {
                return pybind11::cast(get<std::string>(key));
            }
            // 可扩展添加更多支持的数据类型分支
            throw std::runtime_error("Unsupported data type for this key");
        }
    };
    
  2. 用pybind11绑定适配方法并命名为get
    在pybind11的模块绑定代码中,将get_py方法暴露为Python端的get方法,这样Python代码就可以直接调用map.get(key):

    PYBIND11_MODULE(my_map_module, m) {
        pybind11::class_<Map>(m, "Map")
            .def(pybind11::init<>())
            .def("set", &Map::set<int>)
            .def("set", &Map::set<std::string>)
            // 按需绑定更多类型的set方法
            .def("get", &Map::get_py);
    }
    

效果验证

编译生成模块后,在Python中即可直接使用:

from my_map_module import Map

map = Map()
map.set("my-int-entry", 42)
map.set("my-string-entry", "hello")

a = map.get("my-int-entry")
print(type(a))  # 输出 <class 'int'>
b = map.get("my-string-entry")
print(type(b))  # 输出 <class 'str'>

如果你的Map类内部有自己的类型存储机制(而非示例中的std::any),只需调整get_py方法中的类型判断逻辑即可,核心是在C++层完成运行时类型的分发工作。


内容的提问来源于stack exchange,提问作者user3207838

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 07:45:35