Python 来自boost预处理器的带预处理器宏的SWIG

Python 来自boost预处理器的带预处理器宏的SWIG,python,c++,boost,macros,swig,Python,C++,Boost,Macros,Swig,我正在使用此处建议的enum with ToString实现: 据我所知,它使用和运作良好 当我尝试包装宏并将其导出到用SWIG包装的Python库时,就会出现问题。类似问题: 在那里,解决方案是向SWIG接口添加标题/声明。到目前为止,我还没有在这方面取得成功。很可能我只是不知道我要补充什么 尝试: %include <boost/preprocessor/config/config.hpp> %include <boost/preprocessor/stringize.hp

我正在使用此处建议的enum with ToString实现: 据我所知,它使用和运作良好

当我尝试包装宏并将其导出到用SWIG包装的Python库时,就会出现问题。类似问题: 在那里,解决方案是向SWIG接口添加标题/声明。到目前为止,我还没有在这方面取得成功。很可能我只是不知道我要补充什么

尝试:

%include <boost/preprocessor/config/config.hpp>
%include <boost/preprocessor/stringize.hpp>
%include <boost/preprocessor/seq/for_each.hpp>
%include <boost/preprocessor/seq/enum.hpp>
这个错误不是很具有指示性。第29行是my_enum的实际定义

matthias@rp3deb:~/dvl/swig_boost_minimal$ swig minimal.i
minimal.h:29: Error: Syntax error in input(1).

有关于如何包装的建议吗?

如果您想让SWIG读取boost/preprocessor.hpp,您可以使用:

%module minimal
%{
#include "minimal.h"
%}
%include <boost/preprocessor.hpp>
%include "minimal.h"
和最小值。h:

#ifndef MINIMAL_H
#define MINIMAL_H
#include "enum.h"

DEFINE_ENUM_WITH_STRING_CONVERSIONS(my_enum, (A)(B))
#endif
因此,minimal.cpp仍像以前一样工作,但现在我们可以编写一个至少可以编译的SWIG模块,即使它还没有做任何有用的事情:

%module minimal
%{
#include "minimal.h"
%}
%define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name,enumerators)
%enddef
%include "minimal.h"
目前有一个存根,SWIG特定的宏,我们将要填写。我这样做有点难看,因为我试图避免改变现有宏的定义/使用方式

作为起点,我生成了另一个文件enum.I:

%include
%包括
%{
#包括
#包括
#包括
%}
%使用字符串转换(名称、枚举数)定义枚举
%{
typedef std::元组名称###(u项);
结构名称####辅助对象{
std::向量表;
名称###辅助对象(常量名称值){
list.push_back(std::make_tuple(value),ToString(value));
}
名称###U辅助运算符()(常量名称值){
list.push_back(std::make_tuple(value),ToString(value));
归还*这个;
}
};
静态常量std::vector name###u list=name###u helper枚举器。list;
%}
结构名称###u项{
%延伸{
常量无符号长值{
返回std::get(*$self);
}
常量std::字符串和标签{
返回std::get(*$self);
}
}
};
%模板(名称###vec)std::vector;
const std::向量名###u列表;
%enddef
如此之少。我只需要成为:

%module minimal

%{
#include "minimal.h"
%}

%include "enum.i"
%include "minimal.h"

所有宏都取<代码>枚举器< /C> >的值,这将是类似于(a)(b)< /> >的代码,并生成一些完全标准的代码(如果是奇数),C++将此代码扩展为<代码> STD::vector < /代码>。这是通过将第一个枚举成员映射到构造函数调用,将其余成员映射到重载的

操作符()
来实现的。我们使用enum.h提供的
ToString()
来查找字符串表示形式。最后,我们的宏有足够的信息来包装元组向量,这在Python中是有意义的

有了这一点,我们可以做如下事情:

导入最小值
打印“,”.join(“%s(%d)”%(x.label,x.value)用于最小.my_enum_列表中的x)
在编译和运行时,它给出:

A(0),B(1)

即足以开始编写Python代码,它既知道标签的值又知道C++的值。 但我们不要就此止步!为什么我故意调用结果向量

my_enum\u list
,而不只是
my_enum
?因为我们现在能做的更多

Python2.7没有任何默认的“enum-ish”,但这并不妨碍我们将其包装为对了解enum的人来说既有Pythonic又自然的东西。我通过阅读获得了对Python2.7Enum的支持。首先,我使用
%pythoncode
(在最终源代码中标记为#1)向文件中添加了一些通用枚举支持例程,但不在SWIG宏之外,因为不需要更改它。我还在SWIG宏(标记为#2)中添加了一个
%pythoncode
,该宏在每个实际枚举中调用一次。为了完成这项工作,我必须将以前版本中的
const std::vector
转换为一个函数,以便在生成的Python的正确部分可以访问它。最后,我必须向SWIG展示一个实数enum的前向声明,以便说服它实际接受它作为函数的参数。最终结果是:

%include
%包括
%{
#包括
#包括
#包括
%}
// #1
%蟒蛇代码%{
类枚举值(int):
定义新定义(cls、v、l):
结果=超级(枚举值,cls)。\uuuu新的\uuuuu(cls,v)
结果。_值=l
返回结果
定义(自我):
返回自我值
def make_枚举(名称、枚举):
返回类型(名称,(),枚举)
%}
%使用字符串转换(名称、枚举数)定义枚举
%{
typedef std::元组名称###(u项);
结构名称####辅助对象{
std::向量表;
名称###辅助对象(常量名称值){
list.push_back(std::make_tuple(value),ToString(value));
}
名称###U辅助运算符()(常量名称值){
list.push_back(std::make_tuple(value),ToString(value));
归还*这个;
}
};
静态常量std::向量名###(u list){
返回名称####辅助枚举器。列表;
}
%}
结构名称###u项{
%延伸{
常量无符号长值{
返回std::get(*$self);
}
常量std::字符串和标签{
返回std::get(*$self);
}
}
};
%模板(名称###vec)std::vector;
常量std::向量名###(u list());
// #2
%蟒蛇代码%{
name=make_enum('name',{x.label:EnumValue(x.value,x.label)表示名称###u list()}中的x)
%}
枚举名;
%enddef
我在minimal中添加了一个函数。我想证明它确实有效:

%模块最小值
%{
#包括“minimal.h”
%}
%包括“enum.i”
%包括“minimal.h”
%内联%{
void foo(const my_enum&v){

我几乎有一个答案,但出于好奇,你是针对Python2.x还是3.x?我仍然使用Python2.7。上次考虑切换时(不久前),Python 3仍然缺少我需要的一些库。这是一个非常好的答案,我相信它可以工作。不幸的是,它有点忽略了这个问题。它创建了大量重复代码,并没有解决包含boost头的问题。我想我希望有一种方法可以很好地包含正确的boost头。有这么多但是,这一定很乏味。
#ifndef ENUM_H
#define ENUM_H
#include <boost/preprocessor.hpp>

//Found this here: https://stackoverflow.com/questions/5093460/how-to-convert-an-enum-type-variable-to-a-string
#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE(r, data, elem)    \
    case elem : return BOOST_PP_STRINGIZE(elem);

#define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name, enumerators)                \
    enum name {                                                               \
        BOOST_PP_SEQ_ENUM(enumerators)                                        \
    };                                                                        \
                                                                              \
    inline const char* ToString(name v)                                       \
    {                                                                         \
        switch (v)                                                            \
        {                                                                     \
            BOOST_PP_SEQ_FOR_EACH(                                            \
                X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE,          \
                name,                                                         \
                enumerators                                                   \
            )                                                                 \
            default: return "[Unknown " BOOST_PP_STRINGIZE(name) "]";         \
        }                                                                     \
    }
#endif
#ifndef MINIMAL_H
#define MINIMAL_H
#include "enum.h"

DEFINE_ENUM_WITH_STRING_CONVERSIONS(my_enum, (A)(B))
#endif
%module minimal
%{
#include "minimal.h"
%}
%define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name,enumerators)
%enddef
%include "minimal.h"
%module minimal

%{
#include "minimal.h"
%}

%include "enum.i"
%include "minimal.h"