我一直在我的C ++头文件中使用this answer中的REFLECTABLE
宏,如下所示:
#ifndef TIMER_H
#define TIMER_H
// From the linked question, but (deliberately) ignored by SWIG here,
// only relevant is as much as it defines REFLECTABLE for other preprocessors
#include "reflection.hh"
struct Timer {
REFLECTABLE (
(float) startTime,
(float) endTime,
)
};
#endif
SWIG预处理器不遵循#include
并且无法处理来自链接问题的REFLECTABLE定义,因此我的计划是完全忽略它并用更合适的SWIG特定REFLECTABLE定义替换它
我的目标是让SWIG preprocessor扩展Timer,好像没有什么特别的事情发生,即:
struct Timer {
float startTime;
float endTime;
};
为此,我编写了一个简单的reflection.i,它对%define
SWIG宏进行递归调用:
#define REM(...) __VA_ARGS__
#define PAIR(x) REM x
%define EXPAND(tail, ...)
PAIR(tail);
EXPAND(__VA_ARGS__)
%enddef
#define REFLECTABLE(...) EXPAND(__VA_ARGS__)
我可以在test.i中使用:
%module test
%include "reflection.i"
%include "timer.h"
当我们运行swig -python -Wall -E test.i
来检查通过SWIG预处理器运行它的结果时,它几乎可以工作,但递归结束时的定义与我想要的不完全匹配:
struct Timer {
/*@SWIG:reflection.i,4,EXPAND@*/
float startTime;
/*@SWIG:reflection.i,4,EXPAND@*/
float endTime;
EXPAND
};
问题是当EXPAND
为空时,匿名___VA_ARGS__
会终止递归。我查看了使用this answer中的map.h,但这也不适用于SWIG预处理器。
如何修改REFLECTABLE
的定义,以便SWIG预处理器只生成我正在寻找的扁平结构?
答案 0 :(得分:1)
我最终提出了一个解决方案,需要进行两项更改:
递归的间接性更强,我们将两个令牌粘贴在一起以获取令牌EXPAND_STOP
或EXPAND_MORE
,具体取决于此评估期间__VA_ARGS__
是否为空。此选择是因为SWIG评估
#define STOP(...) MORE
当有参数时,为MORE
,但在没有参数时,只需为STOP。
然后TOKEN
宏添加了令牌粘贴运算符所需的间接功能。
EXPAND_MORE
和EXPAND_STOP
都有一个假的第一个参数,它阻止了同样的行为阻止我们在没有参数的情况下对EXPAND_STOP
进行调用。
#define REM(...) __VA_ARGS__
#define PAIR(x) REM x
#define TOKEN_(x,y) x##y
#define TOKEN(x,y) TOKEN_(x, y)
#define STOP(...) MORE
%define EXPAND_MORE(fake, ...)
EXPAND(__VA_ARGS__)
%enddef
#define EXPAND_STOP(fake, ...)
%define EXPAND(tail, ...)
PAIR(tail);
TOKEN(EXPAND_, STOP(__VA_ARGS__)) ## (fake, ##__VA_ARGS__)
%enddef
#define REFLECTABLE(...) EXPAND(__VA_ARGS__)
虽然可能不是最优雅的解决方案,但已经过测试并使用SWIG 3.0.2。