如何实现EXCLUDE
以下代码在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预处理器缺少参数预扫描功能还是MSVC违反了一些c ++标准?
我怎样在使用MSVC时实现这个EXCLUDE_FIRST_ARG功能?
这是因为MSVC预处理器缺少参数预扫描功能还是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。 参数替换
在EXCLUDE_FIRST_ARG
的替换列表中提及__VA_ARGS__
。 它没有被串化或参与粘贴。 这使得它有资格进行参数替换。 在替换参数之前,表达式:
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)
...重新扫描以获取更多宏。 在此重新扫描期间,预处理器注意到用“参数” a, b, c, d, e
(对其他主要预处理器,这是五个参数)调用类似对象的宏_EXCLUDE_FIRST_ARG_
。
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__
(未被__VA_ARGS__
化/粘贴)不符合MS的逗号省略功能,因此空的可变参数会导致__VA_ARGS__
被__VA_ARGS__
替换。
对于大多数其他主要预处理程序,还是有不提first
替换列表中,所以什么也没发生,以a
。 __VA_ARGS__
(未被__VA_ARGS__
化/粘贴)被提及,所以b, c, d, e
被评估,导致b, c, d, e
; 该结果取代__VA_ARGS__
。
2c.c. 重新扫描并进一步更换
对于MS的预处理器,这里没有什么有趣的。 自完成后,地标将被删除。
对于其他预处理器, b, c, d, e
再次被重新扫描,导致相同的结果。
在这种情况下,您可以使用助手将参数列表从宏中分离出来:
#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
在这个方法的阶段扩展为CALL(_EXCLUDE_FIRST_ARG_,(a, b, c, d, e))
。 在重新扫描期间,在每次完全评估后,调用CALL
(在此期间扩展为_EXCLUDE_FIRST_ARG_
和(a, b, c, d, e)
。 然后在CALL
的重新扫描期间,参数列表再次看起来像多个标记。