我一直在寻找一种方法来检查可变参数宏参数列表是否为空。我发现的所有解决方案似乎都非常复杂或使用非标准扩展。
我想我找到了一个既紧凑又标准的简单解决方案:
#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
问:在任何情况下我的解决方案都会失败或调用定义不明确的行为吗?
基于C17 6.10.3.2/2(#运算符):“对应于空参数的字符串文字是""
”,我相信#__VA_ARGS__
总是很明确。
宏的解释:
""
,其仅包含空终止符,因此大小为1。注意:此答案的此版本是重写的结果。一些声明已被删除,其他声明已被大幅修改,以便集中注意并更好地证明最重要的观点。
[有争议的,有争议的立场被删除。这更令人分心而不是有用。]
我想我找到了一个既紧凑又标准的简单解决方案:
#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
我们可以通过考虑这种变化来回避任何不确定性的问题:
#define is_empty(dummy, ...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
。同样的注意事项适用于空白与非空变量参数的解释,就像在原始版本中一样。特别,
基于C17 6.10.3.2/2(#运算符):“对应于空参数的字符串文字是”“”,我相信
#__VA_ARGS__
总是很明确。
我同意。此处的相关内容也是第6.10.3.1/2节:“替换列表中出现的标识符__VA_ARGS__
应被视为参数[...]。”
宏的解释:
- 这将创建一个复合文字char数组,并使用字符串文字对其进行初始化。
是。
- 无论传递给宏的是什么,所有参数都将被转换为一个长字符串文字。
是。 __VA_ARGS__
被视为(一)参数。如果存在多个变量参数,那么可能会影响重新扫描,但是在重新扫描之前,字符串化运算符会在宏扩展点产生影响。
- 如果宏列表为空,则字符串文字将变为“”,其仅包含空终止符,因此大小为1。
是。
- 在所有其他情况下,它的大小将大于1。
是。即使在变量参数列表is_empty(dummy,,)
中有两个零令牌参数的情况下也是如此,其中#__VA_ARGS__
将扩展为","
。它也适用于由空字符串文字is_empty(dummy, "")
组成的参数,其中#__VA_ARGS__
将扩展为"\"\""
。
但是,这仍然可能无法满足您的目的。特别是,您不能在条件编译指令中使用它。虽然sizeof
表达式通常允许在整数常量表达式中,例如形成此类指令的控制表达式,
sizeof
被归类为标识符(预处理令牌的关键字和标识符之间没有区别),以及因此,如果您的宏被用作条件编译指令的控制表达式,那么它将被评估为好像其中的sizeof
运算符被0
替换,从而产生无效表达式。
我个人不喜欢混合宏/预处理器级评估和编译级测试。
似乎没有标准的方法在宏观层面上做到这一点,但这里存在黑客攻击:C++ preprocessor __VA_ARGS__ number of arguments