在参数的默认值中使用参数名 - 是否合法?

11
enum class E {
    One,
    Two
};

void foo(E value = decltype(value)::One) {
}

它可以使用Clang(3.9)进行编译,但不能使用GCC 6.1进行编译:value was not declared in this scope

哪个编译器是正确的?


看起来这个是答案,但我不确定百分之百。让其他人决定是否应该将其关闭为重复。 - NathanOliver
@NathanOliver 那个问题涉及访问参数的值,由于良好的原因(评估顺序)这是不可能的,但我期望它的名称和类型受到不同规则的约束,因为这个原因并不影响它们。 - Quentin
@Quentin,这就是为什么我没有投票关闭的原因。标准中的引用是“因此,函数的参数不得在默认参数表达式中使用,即使它们没有被评估。”我不确定这是否适用于此处。 - NathanOliver
@NathanOliver int h(int a, int b = sizeof(a)); 在一个示例中被用作错误,因此我认为这是不允许的。 - krzaq
@Columbo 很有趣,它在 N4606 中被注释为“Ok”,但在 4140 中出现错误。 - krzaq
显示剩余3条评论
1个回答

9
根据[basic.scope.pdecl]/1
声明名称的声明点是在其完整的声明符(第8条款)之后,在其初始化器(如果有的话)之前,除非下面有说明。
因此参数在那一点上肯定已被声明。在decltype中使用它怎么样?措辞已经过时并无意中禁止了它。请参见core issue 2082

According to 8.3.6 [dcl.fct.default] paragraph 9,

A default argument is evaluated each time the function is called with no argument for the corresponding parameter. The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in a default argument, even if they are not evaluated. This prohibits use of parameters in unevaluated operands, e.g.,

void foo(int a = decltype(a){});

This wording predates the concept of “unevaluated operands” (the phrase “not evaluated” refers to calls to the function where an actual argument is supplied and thus the default argument is not used, not to unevaluated operands) and should not apply to such cases.

因此,引用段落已被修改为:

参数不得出现在默认参数的潜在求值表达式中。

由于decltype的操作数是未求值的,所以现在这样做是可以的,而GCC是错误的。


1
这只是在草案中引入的,而不是在C++14中引入的。http://wg21.cmeerw.net/cwg/issue2082 - vladon
@vladon 是的,我在 krzaq 的评论之后也发现了这个问题。 - Columbo
GCC 真的错了吗?还是只需要更新它在 C++17/1z 上的编译方式?看起来在 C++14 中被禁止了,所以你真的不能因此指责 GCC。 - NathanOliver
@NathanOliver 是的,你可以;核心缺陷解决必须及时实施,因为它们涉及语言中的实际不一致性。此外,仅仅将所有缺陷解决推迟到新标准发布有何意义? - Columbo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接