X 宏中元素的条件定义

2022-01-11 00:00:00 macros c++ c-preprocessor

想象一下,我有一个 X Macro 用于定义如下项目的列表:

Imagine I have an X Macro for a list of items defined something like this:

#define X_MACRO(FN) 
  FN(foo) 
  FN(bar) 
  FN(zip)

这很好用,我可以调用它来为每个元素生成相同的模板化代码,例如:

This works great and I can call it to generate the same code templatized for each element, like:

#define xstr(s) str(s)
#define str(s) #s
#define PRINT_X(E) void print_ ## E () { std::cout << str(E); }; 
X_MACRO(PRINT_X)

这会生成像 void print_foo() { std::cout << 这样的函数.富";}; 用于每个 X_MACRO 元素.到目前为止,一切顺利.

This generates functions like void print_foo() { std::cout << "foo"; }; for each of the X_MACRO elements. So far, so good.

但是,现在,我希望 X 宏元素的列表以预处理器宏为条件.例如,如果定义了 USE_ZIP,则 zip 元素应该只包含在 X 宏中.当然,我不能在X宏里面放一个#ifdef,比如:

Now, however, I want the list of X Macro elements to be conditional on a pre-processor macro. For example the zip element should only be included in the X Macro if USE_ZIP is defined. Of course, I can't put an #ifdef inside the X Macro, like:

#define X_MACRO(FN) 
  FN(foo) 
  FN(bar) 
#ifdef USE_ZIP
  FN(zip)
#endif

我可以将列表写入两次,一次使用 zip,一次不使用,基于 USE_ZIP,如下所示:

I could instead write the list twice, once with zip and once without, based on the USE_ZIP like so:

#ifdef USE_ZIP
#define X_MACRO(FN) 
  FN(foo) 
  FN(bar) 
  FN(zip)
#else
#define X_MACRO(FN) 
  FN(foo) 
  FN(bar)
#endif

...但这违反了 DRY,更重要的是,如果您需要有条件地包含其他元素,它会迅速失控,这将需要 USE_* 宏的每个可能组合的列表.

... but this violates DRY and more importantly it rapidly spirals out of control if you need to conditionally include other elements, which would require a list for each possible combination of USE_* macros.

我怎样才能以合理的方式做到这一点?

How can I do this in a reasonable way?

推荐答案

做到这一点的一种方法是以 base 样式拆分事物并从超级宏中调用它(我不知道如果它们有特殊名称):

One way to do this is to split things in a base style and call it from a super macro (I don't know if these have special names):

#define X_MACRO_BASE(fn) 
    fn(foo) 
    fn(bar) 

#if USE_ZIP

#define X_MACRO(fn) 
    X_MACRO_BASE(fn) 
    fn(zip)

#else

#define X_MACRO(fn) 
    X_MACRO_BASE(fn)

#endif

它并不完美,但它仍然可能有用:-)

It's not perfect, but it still might be useful :-)

另一个巧妙的技巧是有一个简单的条件宏(比如 USE_ZIP0 还是 1):

Another neat trick is to have a simple conditional macro (say if USE_ZIP was 0 or 1):

#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, foo) IF_ ## cond (foo)
#define IF_0(foo)
#define IF_1(foo) foo

那么你可以说:

#define X_MACRO(fn) 
    fn(foo) 
    fn(bar) 
    IF(USE_ZIP, fn(zip))

相关文章