C++20标准中为何会忽略函数的void形参?
问题背景与疑问
我正在开发一个框架,允许用户注册函数并由框架代为调用。该框架仅接受至少包含一个形参的函数,以此减少副作用过多的函数。我通过编译期检查函数的输入参数数量实现了这一限制,代码如下:
template <typename R, typename... Args> constexpr std::size_t number_input_parameters(R (*)(Args...)) { return sizeof...(Args); }
使用示例:
int no_parameters() {} // 会被框架拒绝 static_assert(number_input_parameters(no_parameters) == 0);
开发时我担心形如int still_no_parameters(void) {}的函数——这类函数看起来声明了一个void形参,但按需求也应该被框架拒绝。实际测试后发现,上述实现给出了正确结果(在Clang 15和GCC 12中):
static_assert(number_input_parameters(still_no_parameters) == 0);
显然编译器将R(void)类型的函数解析为了R()类型,想了解在C++20标准中,是如何规定要忽略函数的void形参的?
C++20标准中的相关规定
在C++20标准的【dcl.fct】条款中明确了这一行为:
由单个未命名的
void类型参数构成的参数列表,等价于空参数列表。除了这个特殊情况外,参数不能是cv限定的void类型。
这一规定是为了兼容C语言的写法:在C语言中,f(void)明确表示函数不接受任何参数,而f()表示参数数量和类型未指定;但在C++中,f()本身就表示无参数函数,同时保留了f(void)作为等价写法,以此兼容C代码的习惯。
对应到场景中,int still_no_parameters(void)的函数类型会被编译器视为int(),因此模板推导时Args...会被推导为空参数包,sizeof...(Args)的结果为0,符合对无参数函数的判断逻辑,从而正确拒绝这类函数。
内容的提问来源于stack exchange,提问作者Kyle Knoepfel
相关产品推荐
相关产品推荐

