SWIG - 当方法具有枚举类型参数时出现 OverflowError

SWIG - OverflowError when methods have enum typed arguments

我有一个 C++ 代码库,它使用 SWIG 生成 Python 3 个接口。

我有一个 无法将 enum 值转换为足够大的类型。在很好的帮助下解决了这个问题。

现在我有一个与另一个问题相关的新问题。当最大的 enum 值作为参数传入时,将更正后的 enum 值作为参数的方法将抛出 OverflowError

我想知道是否有使用 typemap 函数解决此问题的通用方法(就像枚举对象的方法)。识别所有将 enum 常量作为参数的方法。或者我是否需要为每个 enum 类型定义一个 in typemap

我已经尝试过并且有效的方法是将其包含在 .i 文件中:

%include "typemaps.i"
%apply unsigned long long { doom::Bar::FooPresence };

但如果有一种“包罗万象”的东西就好了,比如 constcode 类型映射。

重现当前行为所需的代码:

bar.h


namespace doom
{
class Bar
{
public:
    struct FooIdent
    {
        enum Ident
        {
            UnknownFoo = 0,
            KnownFoo = 1,
            MainFoo = 2,
            SecondaryFoo = 3
        };
    };

    enum FooPresence
    {
        Boo = 0x0,
        Foo1 = 0x8000000000ULL,
        Foo2 = 0x4000000000ULL,
        Foo3 = 0x2000000000ULL,
        FooWithA1 = 0x1000000000ULL,
        FooWithA2 = 0x0800000000ULL,
        FooWithA3 = 0x0400000000ULL,
        FooWithA4 = 0x0200000000ULL,
        FooWithB1 = 0x0100000000ULL,
        FooWithB2 = 0x0080000000,
        FooWithB3 = 0x0040000000
    };

    Bar();

    void setVesODee( int ves, doom::Bar::FooPresence pr );
    void setVesOGoo( int goo, doom::Bar::FooIdent::Ident ide );
    int doSomething();

private:
    int m_vdee;
    int m_vgoo;
};
} // namespace doom

bar.cpp

#include "bar.h"
#include <iostream>

namespace doom
{

Bar::Bar()
{
    m_vdee = 0;
    m_vgoo = 0;
}

void Bar::setVesODee( int ves, doom::Bar::FooPresence pr ) {
    m_vdee = static_cast< doom::Bar::FooPresence >( ves & pr );
}

void Bar::setVesOGoo( int goo, doom::Bar::FooIdent::Ident ide ) {
    m_vgoo = static_cast< doom::Bar::FooIdent::Ident >( goo & ide );
}

int Bar::doSomething() {
    return m_vgoo + m_vdee;
}

} // namespace doom


int main() {
    doom::Bar b = doom::Bar();

    b.setVesODee(3, doom::Bar::FooWithB2);
    b.setVesOGoo(4, doom::Bar::FooIdent::MainFoo);

    int c = b.doSomething();
    std::cout << c << std::endl;

    return 0;
}

bar.i

%module bar

%feature ("flatnested");

%{
#define SWIG

#include "bar.h"

#define SWIG_PYTHON_STRICT_BYTE_CHAR
%}


%typemap(constcode) int %{
    SWIG_Python_SetConstant(d, "$symname", PyLong_FromLongLong(static_cast<long long>()));
%}

%rename("Bar_%s", %$isnested) "";
%include "bar.h"

test_bar.py

import bar

b = bar.Bar()
b.setVesODee(10, bar.Bar.Foo1)

build-and-test.sh

#!/bin/bash
set -e

echo "Cleanup..."
rm -rf __pycache__
rm -f _bar.so bar.o bar_wrap.*

echo "Building..."
swig -python -c++ -py3 -debug-tmsearch bar.i
g++ -fPIC -c $(pkg-config --cflags --libs python3) bar.cpp bar_wrap.cxx
g++ -shared -o _bar.so bar.o bar_wrap.o

echo "Testing..."
python3 test_bar.py

output

Traceback (most recent call last):
  File "test_bar.py", line 15, in <module>
    b.setVesODee(10, bar.Bar.Foo1)
  File "/workspace/ctmp/bar.py", line 83, in setVesODee
    return _bar.Bar_setVesODee(self, ves, pr)
OverflowError: in method 'Bar_setVesODee', argument 3 of type 'doom::Bar::FooPresence'

SWIGTYPE 是未找到 type-specific 匹配时的默认类型匹配。您可以使用以下内容应用于所有枚举:

%apply unsigned long long { enum SWIGTYPE };

参见 13.3.3 Default typemap matching rules in the SWIG documentation

示例:

test.i

%module test

%typemap(constcode) int %{SWIG_Python_SetConstant(d, "",PyLong_FromLongLong(static_cast<long long>()));%}
%apply unsigned long long { enum SWIGTYPE };

%{
#include <iostream>
%}

%inline %{
enum FooPresence : unsigned long long
{
    Foo1 = 0x8000000000ULL,
};

void func(FooPresence x) {
    std::cout << std::hex << static_cast<unsigned long long>(x) << std::dec << std::endl;
}

%}

演示:

>>> import test
>>> test.func(test.Foo1)
8000000000