以下代码在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时,结果是空的。
当我在first
中检查_EXCLUDE_FIRST_ARG_
个参数时,我发现参数a, b, c, d, e
都绑定到first
参数,而左...
没有任何参数。
这是因为MSVC预处理器缺少Argument Prescan功能还是MSVC违反了某些c ++标准?
如何在使用MSVC时实现此 EXCLUDE_FIRST_ARG 功能?
答案 0 :(得分:2)
这是因为MSVC预处理器缺少Argument预扫描功能还是MSVC违反了某些c ++标准?
这是最好的方式,因为我已经能够在微软中将它拼凑在一起。
<强> 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
通过参数替换规则,替换替换列表中的参数“name”。一旦发生这种情况,我们就有了这个:
_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
相关联。可变参数...
为空。
对于大多数其他主要预处理器,使用五个参数调用它。 first
与a
相关联; ...
与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.在每个完全评估后,展开到_EXCLUDE_FIRST_ARG_
和(a, b, c, d, e)
。然后在CALL
重新扫描期间,参数列表再次看起来像多个令牌。