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

使用Boost Python暴露含std::list枚举成员的结构体时赋值失败的问题求助

使用Boost Python暴露含std::list枚举成员的结构体时赋值失败的问题求助

嘿,我一看你这个报错就知道问题出在哪了——你写的from_python_list_enum转换器是把Python列表里的元素当成原生int来处理的,但实际上Python里的my_package.Tag.April是Boost Python包装后的枚举对象,不是普通的int,所以boost::python::extract<int>会直接失败,导致转换器认为这个列表不符合要求,最终抛出类型不匹配的错误。

核心问题分析

你之前处理int列表没问题,是因为Python原生int可以直接被extract<int>提取,但Boost包装的枚举对象不一样,它是一个特殊的Python对象,得用对应的枚举类型E来提取才行。

解决方案

我们只需要修改from_python_list_enum里的convertible和construct函数,让它们能正确识别并处理Boost包装的枚举对象:

1. 修改convertible函数,检查元素是否为目标枚举类型

把原来检查int的逻辑改成检查枚举类型E:

static void* convertible(PyObject* obj_ptr)
{
    if (!PyList_Check(obj_ptr)) {
        return nullptr;
    }
    size_t sz = PySequence_Size(obj_ptr);
    for (size_t i = 0; i < sz; ++i)
    {
        PyObject* item = PyList_GetItem(obj_ptr, i);
        // 直接检查是否能提取为枚举类型E
        if (!boost::python::extract<E>(item).check())
            return nullptr;
    }
    return obj_ptr;
}

2. 修改construct函数,直接提取枚举类型

不需要先转成int再强转,直接提取枚举值:

static void construct(PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data)
{
    typedef boost::python::converter::rvalue_from_python_storage<std::list<E>> storage_type;
    void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
    data->convertible = new (storage) std::list<E>();
    std::list<E>* l = reinterpret_cast<std::list<E>*>(storage);
    size_t sz = PySequence_Size(obj_ptr);
    for (size_t i = 0; i < sz; ++i)
    {
        PyObject* item = PyList_GetItem(obj_ptr, i);
        // 直接提取枚举类型E的值
        E v = boost::python::extract<E>(item);
        l->push_back(v);
    }
}

进阶:同时支持枚举对象和int值

如果你想让用户既可以传[my_package.Tag.April, my_package.Tag.QR],也可以传对应的int值(比如[1, 0]),可以把转换器改成兼容两种情况:

修改后的convertible函数:

static void* convertible(PyObject* obj_ptr)
{
    if (!PyList_Check(obj_ptr)) {
        return nullptr;
    }
    size_t sz = PySequence_Size(obj_ptr);
    for (size_t i = 0; i < sz; ++i)
    {
        PyObject* item = PyList_GetItem(obj_ptr, i);
        // 同时检查是否是枚举对象或者int
        bool is_valid_enum = boost::python::extract<E>(item).check();
        bool is_valid_int = boost::python::extract<int>(item).check();
        if (!is_valid_enum && !is_valid_int)
            return nullptr;
    }
    return obj_ptr;
}

对应的construct函数:

static void construct(PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data)
{
    typedef boost::python::converter::rvalue_from_python_storage<std::list<E>> storage_type;
    void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
    data->convertible = new (storage) std::list<E>();
    std::list<E>* l = reinterpret_cast<std::list<E>*>(storage);
    size_t sz = PySequence_Size(obj_ptr);
    for (size_t i = 0; i < sz; ++i)
    {
        PyObject* item = PyList_GetItem(obj_ptr, i);
        E v;
        // 优先提取枚举类型,不行再转int
        if (boost::python::extract<E>(item).check())
        {
            v = boost::python::extract<E>(item);
        }
        else
        {
            int int_val = boost::python::extract<int>(item);
            v = static_cast<E>(int_val);
        }
        l->push_back(v);
    }
}

验证修改

把上面的代码替换掉原来的转换器实现,重新编译你的包,然后再运行Python代码:

import my_package
options = my_package.Options()
options.tags = [my_package.Tag.April, my_package.Tag.QR]
# 试试传int值也能生效:options.tags = [1, 0]

这次应该就能正常赋值,不会再抛出类型不匹配的错误了。

备注:内容来源于stack exchange,提问作者Cyril

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 06:10:27