预处理器for_each与SWIG接口

时间:2014-12-24 06:01:45

标签: swig c-preprocessor

我一直在我的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预处理器只生成我正在寻找的扁平结构?

1 个答案:

答案 0 :(得分:1)

我最终提出了一个解决方案,需要进行两项更改:

  1. 递归的间接性更强,我们将两个令牌粘贴在一起以获取令牌EXPAND_STOPEXPAND_MORE,具体取决于此评估期间__VA_ARGS__是否为空。此选择是因为SWIG评估

    #define STOP(...) MORE
    
    当有参数时,

    MORE,但在没有参数时,只需为STOP。

    然后TOKEN宏添加了令牌粘贴运算符所需的间接功能。

  2. EXPAND_MOREEXPAND_STOP都有一个假的第一个参数,它阻止了同样的行为阻止我们在没有参数的情况下对EXPAND_STOP进行调用。

    < / LI>
    #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。