Fed*_*dor 46 c++ compiler-errors language-lawyer function-declaration default-arguments
如果在C++中定义了一个新变量,则可以在初始化表达式中使用该变量的名称,例如:
int x = sizeof(x);
Run Code Online (Sandbox Code Playgroud)
那么函数参数的默认值又如何呢?是否允许通过名称引用参数?例如:
void f(int y = sizeof(y)) {}
Run Code Online (Sandbox Code Playgroud)
该函数在 Clang 中被接受,但在 GCC 中被拒绝,并出现错误:
'y' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
演示: https: //gcc.godbolt.org/z/YsvYnhjTb
这里是哪个编译器?
Vla*_*cow 35
根据 C++17 标准(11.3.6 默认参数)
9 每次调用函数时都会计算默认参数,而相应参数没有参数。参数不得作为默认参数中的潜在计算表达式出现。在默认参数之前声明的函数的参数在范围内,并且可以隐藏命名空间和类成员名称
它提供了以下示例:
int h(int a, int b = sizeof(a)); // OK, unevaluated operand
Run Code Online (Sandbox Code Playgroud)
所以,这个函数声明
void f(int y = sizeof(y)) {}
Run Code Online (Sandbox Code Playgroud)
是正确的,因为在此表达式中sizeof(y),y不是计算操作数,基于 C++17 8.3.3 Sizeof:
1 sizeof 运算符生成其操作数的对象表示形式中的字节数。操作数可以是一个表达式,即一个未计算的操作数(第 8 条),也可以是一个带括号的类型 ID。
和 C++17 6.3.2 声明点:
1 名称的声明点紧接在其完整声明符(第 11 条)之后和其初始值设定项(如果有)之前,除非下面另有说明。
代码看起来并没有格式错误,所以 Clang 没问题。
[基本范围.pdecl]
1名称的声明点紧接在其完整声明符 ([dcl.decl]) 之后和其初始化程序(如果有)之前,除非下面另有说明。
这是正在讨论的臭名昭著的段落。我把它放在这里只是想提一下“除非下面提到的”不包括任何默认参数的提及。所以y是在之前声明的= sizeof(y)。
其他相关段落是
[dcl.fct.默认]
9每次调用函数时都会计算默认参数,而相应参数没有参数。参数不得作为默认参数中的潜在计算表达式出现。在默认参数之前声明的函数的参数在范围内,并且可以隐藏命名空间和类成员名称。
sizeof(y)没有可能被评估,所以这也很好。
鉴于第一段可用作y名称,并且其使用方式并不违法,因此肯定是 GCC 拒绝该代码的某些怪癖。
虽然就我个人而言,我并不认为这是一个巨大的损失。这不是最实用的代码。