可变参数宏(C / C ++预处理器;为简单起见,在本问题中,我将其视为一种单独的语言)被限制为 。本质上,可变参数宏只是具有其参数允许包含逗号的参数的宏。这没有提供直接的方法来计算参数,一一处理参数,等等。这些都是可能,但是需要精心,混乱且编译缓慢的hack,例如{ {3}}。与VA_ARGS
相关的 straightforward 唯一唯一的事情就是将它们传递给可变参数函数。
我的问题是,为什么他们要这样设计?使用任何纯功能语言(如CPP)进行列表的标准方法是cons样式模式匹配:处理列表的第一个参数,然后递归其余的参数,并为空列表提供基本情况。标准委员会成员会非常熟悉这种方法。
为什么CPP的可变参数宏不能采用这种方法?可变参数宏是否只是被视为包装可变参数函数的一种方式,从而无需对参数列表进行操作?是否存在一些根本的问题,使变参宏无法递归会变得不切实际?还是...?
注意:我不是在寻找“因为人们不应该使用可变参数宏”的形式的答案/注释。诸如boost.preprocessor之类的事物的存在表明,有理性的人们想要以平凡的方式使用预处理器。也不要寻找关于为什么其他设计会是一个好/坏主意的个人意见。我正试图从那时起找出实际的原因。
答案 0 :(得分:4)
从C继承到C ++的可变宏。
Clive Feather撰写了将可变宏添加到C的论文。
The paper, N580: Varargs for Function-like Macros状态:
此建议允许宏的作者声明需要使用一个 可变数量的参数,并替换尾随参数 整个。
[...]
有可能提供更多的设施,但这已被保留 以获得进一步的建议。
一个问题是是否应该允许零实际参数 匹配尾随参数。已经决定不允许这样做,因为 这与单独提出的另一个建议比较合适。
因此,计划是添加最需要的功能(可用于填充printf调用的宏),并为以后的论文保留进一步的扩展。
在C ++中,宏是二等公民。 C ++很少采用新的宏语法或功能进行创新,而是找到了无需宏即可解决问题的方法。
C尚未进一步创新。
添加到C中的实际vararg宏来自该论文的衍生论文,但是该论文背后的动机文本最清晰。
答案 1 :(得分:3)
显然,它的意图仅仅是成为可变参数函数的包装器。可变参数宏在C99中引入,然后在C ++ 11中引入。 C99基本原理V5.10 6.10.3提供了以下解释:
C99的新功能: C89引入了一种标准机制,用于定义带有 可变数量的参数,但不允许以任何方式编写相同的宏 属性。例如,无法编写看起来像对printf的调用的宏。
此功能现已可用。宏定义以相同的方式使用省略号来表示 可变参数列表。但是,由于宏替换是文本而不是运行时,因此 不同的机制用于指示在何处替换参数:标识符
__VA_ARGS__
。替换为所有与省略号匹配的参数,包括它们之间的逗号。
尽管__VA_ARGS__
还有其他一些用途,但这可能只是一个巧合。例如,您可以使用可变参数宏来计算初始化列表中存在的项目数。
答案 2 :(得分:1)
已经有几个不错的答案,但是我想对它们进行综合,并提及user694733的一个重点。给定提案文件和语言标准中的描述,似乎该提案的唯一预想用例 委托给了printf风格的可变函数。
该提案提到允许零实际参数“更适合另一个提案”。最初我以为这意味着“不允许零参数允许该提案与另一个提案兼容”,但实际上含义似乎更接近于“允许零参数应成为其他提案的一部分”。虽然我找不到可以参考的提案,但确实找到了a public comment by him,并建议使用__VA_COUNT__
关键字。假设该评论至少代表了他的其他建议的主旨,__VA_COUNT__
是人们希望更详细地使用可变参数宏的一种方式。
N580(及其后继产品)似乎代表了一种流行且无争议的提议,即允许可变参数通过宏传递,而__VA_COUNT__
是更丰富的变异函数预处理(通过{{1 }},MACRO_ARGS_1
等,或通过其他未知机制),只有第一个提案才达成共识。