如何在MSVC中实现EXCLUDE_FIRST_ARGUMENT宏?

时间:2018-01-04 04:50:07

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

以下代码在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 功能?

1 个答案:

答案 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相关联。可变参数...为空。

对于大多数其他主要预处理器,使用五个参数调用它。 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.在每个完全评估后,展开到_EXCLUDE_FIRST_ARG_(a, b, c, d, e)。然后在CALL重新扫描期间,参数列表再次看起来像多个令牌。