【问题标题】:How to implement EXCLUDE_FIRST_ARGUMENT macro in MSVC?如何在 MSVC 中实现 EXCLUDE_FIRST_ARGUMENT 宏?
【发布时间】:2018-01-04 04:50:07
【问题描述】:

以下代码在 GCC 中按预期工作,但在 MSVC 中不正常。

#define _EXCLUDE_FIRST_ARG_(first, ...) __VA_ARGS__
#define EXCLUDE_FIRST_ARG(...) _EXCLUDE_FIRST_ARG_(__VA_ARGS__)

示例:

EXCLUDE_FIRST_ARG(a, b, c, d, e)

将在 GCC 中评估(也在 CLANG 中检查)

b, c, d, e

但是当我在这个例子中使用 MSVC 时,结果是空的。

当我检查_EXCLUDE_FIRST_ARG_中的first参数时,我发现a, b, c, d, e的参数都绑定到first参数,而...什么也没有。

这是因为 MSVC 预处理器缺少 Argument Prescan 功能还是 MSVC 违反了某些 c++ 标准?

在使用 MSVC 时如何实现这个 EXCLUDE_FIRST_ARG 功能?

【问题讨论】:

  • Visual C++ 的哪个版本?
  • @1201ProgramAlarm 2015 和 2017 均经过测试。

标签: c++ gcc visual-c++


【解决方案1】:
这是因为 MSVC 预处理器缺少 Argument Prescan 功能还是 MSVC 违反了某些 c++ 标准?

这是我在 Microsoft 中拼凑起来的最佳工作方式。

1.宏定义:

#define _EXCLUDE_FIRST_ARG_(first, ...) __VA_ARGS__
#define EXCLUDE_FIRST_ARG(...) _EXCLUDE_FIRST_ARG_(__VA_ARGS__)

...显然要定义宏。

2。调用

EXCLUDE_FIRST_ARG(a, b, c, d, e)

MS 的预处理器识别出一个类似函数的宏 EXCLUDE_FIRST_ARG 已定义,因此开始扩展:

2a。参数识别

宏定义有形参...;它使用参数a, b, c, d, e 调用。这是一个没有命名参数的可变参数,因此所有参数都绑定到可变参数。

2b。参数替换

__VA_ARGS__EXCLUDE_FIRST_ARG 的替换列表中被提及。它没有被字符串化或参与粘贴。这使它有资格进行参数替换。替换参数前,表达式:

a, b, c, d, e

...由预处理器评估。这些没有什么特别的(没有进行类似函数的宏调用;并且没有一个参数是类似对象的宏),因此评估是相同的;也就是说,评估的参数是:

a, b, c, d, e

根据参数替换规则,替换替换列表中的参数“名称”。一旦发生这种情况,我们就有了:

_EXCLUDE_FIRST_ARG_(a, b, c, d, e)

到目前为止,所有其他主要预处理器都在做同样的事情。但是 MS 的预处理器在扩展 __VA_ARGS__ 时表现出一种特殊的行为;具体来说,特殊之处在于整个替换只是一个标记。您可能会在该扩展中看到逗号;我也是;但对于 MS 来说,它仍然只是一个令牌。

2[在 b 和 c 之间]。字符串化和粘贴,不分先后

这只是此帐户中的语义占位符。这里是这些操作发生的地方,但由于我们没有做任何事情,在这种情况下什么都不会发生。

2c。重新扫描并进一步更换

在这一步,生成的替换列表本身:

_EXCLUDE_FIRST_ARG_(a, b, c, d, e)

...重新扫描以获取更多宏。在此重新扫描期间,预处理器注意到对象类宏 _EXCLUDE_FIRST_ARG_ 正在使用“参数”a, b, c, d, e 调用(对于其他主要预处理器,这是五个参数)。

2c.a.参数识别

_EXCLUDE_FIRST_ARG_ 有一个命名参数first 和一个可变参数。 注意: 在 C++20 之前的预处理器中,从技术上讲,它必须使用至少 2 个参数调用;许多主要的预处理器(包括 MS)都接受少一个。

对于 MS 的预处理器,它使用一个参数调用:a, b, c, d, e,它与参数 first 相关联。可变参数... 为空。

对于大多数其他主要预处理器,这是用五个参数调用的。 firsta 相关联; ...b, c, d, e

2c.b.参数替换

对于 MS 的预处理器,替换列表中没有提到 first,因此没有对相关参数进行任何处理。 __VA_ARGS__(未被字符串化/粘贴)不符合 MS 的逗号省略功能,因此空的可变参数会导致 __VA_ARGS__ 被替换为地标。

对于大多数其他主要预处理器,替换列表中仍然没有提到first,因此a 没有任何反应。提到了__VA_ARGS__(没有被字符串化/粘贴),所以b, c, d, e被评估,导致b, c, d, e;该结果将替换 __VA_ARGS__

2c.c.重新扫描并进一步更换

对于 MS 的预处理器,这里没有什么有趣的。完成后,地标被移除。

对于其他预处理器,b, c, d, e 再次被重新扫描,结果相同。

在使用 MSVC 时如何实现这个 EXCLUDE_FIRST_ARG 功能?

在这种情况下,您可以使用帮助程序将参数列表与宏分开:

#define _EXCLUDE_FIRST_ARG_(first, ...) __VA_ARGS__
#define CALL(A,B) A B
#define EXCLUDE_FIRST_ARG(...) CALL(_EXCLUDE_FIRST_ARG_,(__VA_ARGS__))

EXCLUDE_FIRST_ARG(a, b, c, d, e)

大致上,EXCLUDE_FIRST_ARG 在 a.s. 中扩展为 CALL(_EXCLUDE_FIRST_ARG_,(a, b, c, d, e))。采用这种方法的阶段。在调用 CALL 的重新扫描期间,在 a.s.在 each 被完全评估后,扩展为 _EXCLUDE_FIRST_ARG_(a, b, c, d, e)。然后在CALL 的重新扫描期间,参数列表再次看起来像多个令牌。

【讨论】:

  • 感谢您的详细解答。
猜你喜欢
  • 2014-08-27
  • 2015-04-17
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
  • 2013-05-06
  • 1970-01-01
相关资源
最近更新 更多