函数默认参数值取决于 C++ 中的参数名称

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 条)之后和其初始值设定项(如果有)之前,除非下面另有说明。

  • @KshitijJoshi 这是编译器的一个错误。 (11认同)

Sto*_*ica 9

代码看起来并没有格式错误,所以 Clang 没问题。

[基本范围.pdecl]

1名称的声明点紧接在其完整声明符 ([dcl.decl]) 之后和其初始化程序(如果有)之前,除非下面另有说明。

这是正在讨论的臭名昭著的段落。我把它放在这里只是想提一下“除非下面提到的”不包括任何默认参数的提及。所以y是在之前声明的= sizeof(y)

其他相关段落是

[dcl.fct.默认]

9每次调用函数时都会计算默认参数,而相应参数没有参数。参数不得作为默认参数中的潜在计算表达式出现。在默认参数之前声明的函数的参数在范围内,并且可以隐藏命名空间和类成员名称。

sizeof(y)没有可能被评估,所以这也很好。

鉴于第一段可用作y名称,并且其使用方式并不违法,因此肯定是 GCC 拒绝该代码的某些怪癖。

虽然就我个人而言,我并不认为这是一个巨大的损失。这不是最实用的代码。

  • 请注意,在 C++11 中,有一个不同的表述:_“函数的参数不得在默认参数中使用,即使它们没有被求值”_。链接:https://timsong-cpp.github.io/cppwp/n3337/dcl.fct.default#9。 (7认同)