在处理之前评估宏参数

时间:2019-09-26 18:19:11

标签: c++ macros arguments conditional-statements precompile

我希望能够从宏生成这些选项:

  1. if(void* temp = func(arg)){ foo(temp, variable);return; }
  2. if(void* temp = func2(arg)){ foo(temp, variable2);return; }
  3. if(void* temp = func3(arg)){ foo(temp, variable3);return; }

以此类推,但是如您所见, 1 是唯一的特殊情况。

我想编写一个以数字为参数并生成此代码行的宏,该代码可能具有远大于3的数字。不幸的是,这需要特殊情况下的构造,如果用户传递1并执行常规如果他们通过任何其他数字。有办法吗?

1 个答案:

答案 0 :(得分:1)

如果您真的想为此使用CPP,这很容易。间接GLUE和间接SECOND宏是您可以使用的核心工具:

#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(_,X,...) X

间接SECOND允许您在预处理器中模式匹配。起作用的方式是构建第一个令牌,通常这只是一个一次性的东西。但是由于扩展是间接的,因此如果您构建的第一个标记是宏,它将首先扩展(即,作为可变参数的参数替换的一部分)。如果该扩展包含逗号,则可以在间接选择第二个参数之前移入“新的”第二个参数。您可以使用它来构建特殊情况。

这是一个使用此结构的cpp模式匹配器,除非参数为1,否则它将返回其参数,在这种情况下,它将扩展为没有标记:

#define NOT_ONE(N) SECOND(GLUE(TEST_IF_1_IS_,N),N)
#define TEST_IF_1_IS_1 ,

使用此宏,您的宏可能是:

#define DISPATCH_CASE(N) \
   if(void* temp = GLUE(func,NOT_ONE(N))){ \
      foo(temp, GLUE(variable,NOT_ONE(N))); \
      return;
   }

Demo (coliru)

更新:Visual Studio版本

但是我在Visual Studio上,我无法使其正常工作。我认为问题在于__VA_ARGS__扩展在Visual Studio上的工作方式不同

对于VS,我发现了另一种特定种类的间接寻址(一种将宏与其参数分开的间接寻址,以便arg列表可以在应用之前在简单的(...)上下文中求值)可以帮助找出用逗号分隔参数。通常,我会在多个宏中重复相同的模式,以避免出现蓝色油漆。

在这里,这翻译成稍微难看的东西:

#define GLUE(A,B) GLUE_C(GLUE_I,(A,B))
#define GLUE_I(A,B) A##B
#define GLUE_C(A,B) A B
#define SECOND(...) SECOND_C(SECOND_I,(__VA_ARGS__,,))
#define SECOND_I(_,X,...) X
#define SECOND_C(A,B) A B

Demo (goldbolt)