SWIG 和 C++ 枚举类

Posted

技术标签:

【中文标题】SWIG 和 C++ 枚举类【英文标题】:SWIG and C++ enum class 【发布时间】:2019-11-13 12:16:20 【问题描述】:

编辑:this 答案解决了问题,但最后我提出了一个更模块化的解决方案。看看吧:)

我从twodiscussions 知道,为了类型安全,应该选择enum class 而不是enum。出于这个原因,我在我的项目中使用它,但是当用 SWIG 包装它们时,我得到了一些我不太喜欢的东西。

给定简单的枚举

enum class type 
    A, B, C, D, E, F, G, H, I
;

.hpp 文件中,例如my_types.hppmy_types.i 文件:

%module my_types
%
#include "my_types.hpp"
%
%include "my_types.hpp"

生成的python文件包含包含

type_A = _my_types.type_A
type_B = _my_types.type_B
type_C = _my_types.type_C
type_D = _my_types.type_D
type_E = _my_types.type_E
type_F = _my_types.type_F
type_G = _my_types.type_G
type_H = _my_types.type_H
type_I = _my_types.type_I

这意味着在 Python 中使用它时我必须这样做

import my_types as mt
mt.type_A

使用它们,这....好吧,在这种情况下还可以,因为type这个词没有那么长,但是对于更长的词,它看起来就不那么好了,而且,我,在每个枚举值的开头都有枚举的名称没有多大意义。

有什么方法可以重命名它们(可能使用%rename),以便使用它们可以像这样简单?

import my_types as mt
mt.A

我不知道在这种情况下如何使用%rename,或者它甚至可以用于此目的。任何帮助,包括关于如何以不同方式做同样事情的想法(可能没有枚举),将不胜感激。谢谢大家。

编辑:一些 cmets 指出,将枚举的名称放在每个枚举名称的前面确实有意义。我想详细说明我为什么说它不(对我)的原因。如果我们考虑一个与枚举相同的模块的情况,那么代码看起来有点多余。由于types 已经是 Python 的模块,所以颜色更好的例子是:

enum class colours 
    Blue, Red
;

并且将按照建议使用包装的代码,如下所示:

import colours
Blue = colours.colours_Blue
Red = colours.colours_Red

在我看来,写colours 来引用BlueRed 是不必要的,因为模块colours 只包含一个“枚举”。换成这个不是更好吗?

import colours
Blue = colours.Blue
Red = colours.Red

答案已经解释了如何实现这一点。我会尽快看看。非常感谢!

编辑:this 答案解决了问题。我想对其进行一些更改并提出一个稍微“模块化”的解决方案:

%pythoncode %
__enum_name = "colours"            # your enumeration's name
__enum = __import__(__enum_name)   # import module
__scope_name = __enum_name + "_"   # scope's name (= "colours_")
__scope_length = len(__scope_name) # length
for name in dir(__enum):
    if name.find(__scope_name) == 0:
        setattr(__enum, name[__scope_length:], getattr(__enum, name))
        delattr(__enum, name) # optional
del name, __enum_name, __enum, __scope_name, __scope_length
%

我认为这可以让您的项目更容易复制和粘贴,其中您有十分之一的枚举:)。同样,基于this 的回答。

【问题讨论】:

“在每个枚举值的开头都有枚举的名称没有多大意义。”为什么? enum class 的好处之一是您不能通过编写 A 来引用第一个值,但您必须编写 type::A。这就是为什么它们也被称为作用域枚举,如果你不想要它,你仍然可以使用无作用域枚举 当然,enum class 要求你写type::A,这使得代码更具可读性。但是我看到它的方式,在 Python 中,如果我有一些名为 type 的模块,我必须导入它,必须编写 type.type_A 对我来说是非常多余的。所以这就是为什么我想摆脱这个。只需type.A 我不想建议“不要这样做”。您的编辑使问题更加清晰 【参考方案1】:

其次,我不完全理解您为什么要删除范围(尽管我猜这是因为在 python 中您已经获得了模块范围,而您在 C++ 中没有)。现在,我不认为%rename 可以工作,因为它不是文本转换。但是,我可以想到两种选择,一种在 C++ 中重命名,另一种在 Python 中重命名。

在 C++ 中重命名

my_types.hpp 更改为:

enum class type 
    A, B, C, D, E, F, G, H, I
;

#ifdef SWIG
constexpr type A = type::A;
constexpr type B = type::B;
constexpr type C = type::C;
constexpr type D = type::D;
constexpr type E = type::E;
constexpr type F = type::F;
constexpr type G = type::G;
constexpr type H = type::H;
constexpr type I = type::I;
#endif

并在命令行中添加-DSWIG 来编译包装器。

在 Python 中重命名

修改my_types.i为:

%module my_types
%
#include "my_types.hpp"
%
%include "my_types.hpp"

%pythoncode %
import my_types
for name in dir(my_types):
    if name.find('type_') == 0:
       setattr(my_types, name[5:], getattr(my_types, name))
       delattr(my_types, name) # optional
del name
%

【讨论】:

“虽然我猜这是因为在 python 中你已经获得了模块范围,而在 C++ 中你没有”。是的,这正是我不太喜欢它们的原因。我已经编辑了问题并首先添加了原始问题中应该包含的内容。 我在编辑中添加了一个扩展答案。非常感谢您的帮助!

以上是关于SWIG 和 C++ 枚举类的主要内容,如果未能解决你的问题,请参考以下文章

为啥包含枚举的 C++ 方法会导致 SWIG/C# 中的 AccessViolationExceptions?

C++ 和枚举以及类成员

C++枚举与字符串转换工具类

C++枚举与字符串转换工具类

C++ 枚举类可以有方法吗?

枚举类中的 c++ 运算符重载