函数默认参数值取决于 C++ 中的参数名称 [重复]

Function default argument value depending on argument name in C++ [duplicate]

提问人:Fedor 提问时间:10/6/2021 最后编辑:Vlad from MoscowFedor 更新时间:10/7/2021 访问量:2397

问:

如果在 C++ 中定义了一个新变量,则可以在初始化表达式中使用该变量的名称,例如:

int x = sizeof(x);

那么函数参数的默认值呢?是否允许在那里通过其名称引用参数?例如:

void f(int y = sizeof(y)) {}

此函数在 Clang 中被接受,但在 GCC 中被拒绝,并出现以下错误:

'y' was not declared in this scope

演示:https://gcc.godbolt.org/z/YsvYnhjTb

哪个编译器就在这里?

c++ 编译器错误 语言律师 函数声明 默认参数

评论

0赞 Language Lawyer 2/10/2022
在参数自己的默认值内使用参数名称 - 合法吗?
0赞 Fedor 2/11/2022
感谢您的参考,这确实是一个非常相似的问题。虽然这个答案似乎更详细。

答:

35赞 Vlad from Moscow 10/6/2021 #1

根据 C++17 标准(11.3.6 默认参数)

9 每次调用函数时都会计算默认参数 没有相应参数的参数。参数应 在默认值中不显示为可能计算的表达式 论点。在默认值之前声明的函数的参数 参数在作用域内,可以隐藏命名空间和类成员名称

它提供了以下示例:

int h(int a, int b = sizeof(a)); // OK, unevaluated operand

因此,此函数声明

void f(int y = sizeof(y)) {}

是正确的,因为在此表达式中,不是基于 C++17 8.3.3 Sizeof 的计算操作数:sizeof(y)y

1 sizeof 运算符生成对象中的字节数 其操作数的表示。操作数可以是表达式、 这是未计算的操作数(第 8 条)或带括号的 类型 ID。

和 C++17 6.3.2 声明点:

1 名称的声明点紧跟在其之后 完整的声明器(第 11 条)和其初始值设定项(如果有)之前, 除非下文另有说明。

评论

1赞 Kshitij Joshi 10/6/2021
但是你如何解释 gcc 给出的错误呢?还是 gcc 中的错误?
11赞 Vlad from Moscow 10/6/2021
@KshitijJoshi 这是编译器的一个错误。
9赞 StoryTeller - Unslander Monica 10/6/2021 #2

代码看起来格式不正确,所以 Clang 没问题。

[基本.scope.pdecl]

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

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

另一个相关段落是

[dcl.fct.默认]

9 每次调用函数时,都会计算一个默认参数,而不计算相应参数的参数。参数不应在默认参数中显示为可能计算的表达式。在默认参数之前声明的函数的参数在作用域中,可以隐藏命名空间和类成员名称。

sizeof(y)没有潜在的评估,所以这也很好。

看到第一段作为名称提供,并且它以一种不非法的方式使用,一定是 GCC 拒绝代码的一些怪癖。y

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

评论

7赞 Daniel Langr 10/6/2021
请注意,在 C++11 中,有一个不同的表述:“函数的参数不应在默认参数中使用,即使它们没有被计算”。链接:timsong-cpp.github.io/cppwp/n3337/dcl.fct.default#9
0赞 StoryTeller - Unslander Monica 10/6/2021
@DanielLangr - 有趣。可能是 g++ 前端的遗留物。不过,它确实接受了该标准的例子。
0赞 Deduplicator 10/7/2021
我认为他们应该取消限制,并让编译器根据需要对默认参数进行排序,以便对其他参数进行潜在评估。至少会简化使用。