在向量模板中引用带有嵌套枚举的结构体

11 投票
1 回答
2277 浏览
提问于 2025-04-17 19:57

这是我在cython用户组提问的一个问题的跨帖,已经过去一天半了,但还没有得到任何回复,所以我想在一个更广泛的论坛试试运气。

我一直在尝试各种方法来包装以下代码,遇到了不同程度的错误。经过大量搜索,我发现了一些类似的问题和一个很棒的愿望清单,但老实说,我不确定自己是否走在正确的道路上。

plow_types.h:

namespace Plow {

    struct JobState {
      enum type {
        INITIALIZE = 0,
        RUNNING = 1,
        FINISHED = 2
      };
    };
    ...
    class JobFilterT {
     public:
      ...
      std::vector<JobState::type>  states;
      ...

我想要包装这个Plow::JobState::type的枚举类型。根据我找到的另一个类似帖子,我的尝试是这样的:

plow_types.pxd:

cdef extern from "rpc/plow_types.h" namespace "Plow":

    enum JobState_type "Plow::JobState::type":
        INITIALIZE "Plow::JobState::INITIALIZE"
        RUNNING "Plow::JobState::RUNNING"
        FINISHED "Plow::JobState::FINISHED"

    struct JobState:
        JobState_type type
    ...
    cdef cppclass JobFilterT:
        vector[JobState_type] states 

但是我遇到了一个错误:

src/plow.cpp: In function ‘std::vector<Plow::JobState::type, std::allocator<Plow::JobState::type> > __pyx_convert_vector_from_py_enum__Plow_3a__3a_JobState_3a__3a_type(PyObject*)’:
src/plow.cpp:6688: error: invalid conversion from ‘long int’ to ‘Plow::JobState::type’

两者之一:

  1. 我该如何正确地包装这个嵌套的枚举?
  2. 我真的有必要这样精确地包装吗?或者我可以通过其他方式来访问这些“命名空间”的常量吗?我是否应该完全忽略这些结构,自己在pyx中定义常量,使用匹配的整数值?

我尝试在我的cython pyx中简单地定义自己的常量版本,并把所有东西都当作整数处理(vector[int] states),但编译器抱怨说不知道如何将int long转换为Plow::JobState::type

1 个回答

8

我终于搞明白了,尝试了无数种组合之后。其实离我在提问前的最后一次尝试并没有太远……

plow_types.pxd:

我只需要忘掉那个 JobState 结构体,专心把枚举类型包裹起来。不过,我还需要在 cython 中把它们映射到新的名字,以避免和其他使用相似命名空间的枚举发生名字冲突。

cdef extern from "rpc/plow_types.h" namespace "Plow":

    ctypedef enum JobState_type "Plow::JobState::type":
        JOBSTATE_INITIALIZE "Plow::JobState::INITIALIZE"
        JOBSTATE_RUNNING "Plow::JobState::RUNNING"
        JOBSTATE_FINISHED "Plow::JobState::FINISHED" 

现在我可以在像 vector[JobState_type] 这样的地方引用 JobState_type。接着,我用这种方法把我的常量在 python 中以只读的方式提供出来:

job.pyx:

cimport cython

@cython.internal
cdef class _JobState:
    cdef:
        readonly int INITIALIZE 
        readonly int RUNNING 
        readonly int FINISHED 

    def __cinit__(self):
        self.INITIALIZE = JOBSTATE_INITIALIZE
        self.RUNNING = JOBSTATE_RUNNING
        self.FINISHED = JOBSTATE_FINISHED

JobState = _JobState()

这样我就得到了一个公共的 JobState 实例,里面有只读的常量属性。

当需要把一组 python 值转换回 vector[JobState_type] 时,我会这样做:

someList = [JobState.RUNNING]
...
cdef:
    JobState_type i
    vector[JobState_type] vec_states

for i in someList:
    vec_states.push_back(i)

撰写回答