【问题标题】:Evaluate a Macro Argument Before Processing在处理之前评估宏参数
【发布时间】:2019-09-26 18:19:11
【问题描述】:

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

  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 并执行一般情况,这需要在特殊情况下构建如果他们通过任何其他数字。有没有办法做到这一点?

【问题讨论】:

  • 为什么不填充函数指针数组而不是宏地狱呢?然后,您可以使用提供的索引在 if 语句中对数组进行索引(第零索引中没有任何内容。)
  • @NathanOliver 肯定有更好的方法可以做到这一点,主要是从使用数组或funcvariable 之间的其他关联开始,但因为我不拥有这里的代码,我认为宏可能更容易,并且不需要我定义自己的映射数组,我可能只会使用其中的 1 个映射。

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


【解决方案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)

【讨论】:

  • 我喜欢这个设计。它超级优雅。但我在 Visual Studio 上,我无法让它工作。我认为问题是 __VA_ARGS__ 扩展在 Visual Studio 上的工作方式不同:( 有没有办法在 Visual Studio 中做到这一点?
猜你喜欢
  • 2016-05-08
  • 2019-07-02
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多