Using a parameter's name inside its own default value - is it legal?
Asked Answered
B

1

11
enum class E {
    One,
    Two
};

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

It can be compiled with Clang (3.9), but cannot be compiled with GCC 6.1: value was not declared in this scope.

What compiler is right?

Badlands answered 9/11, 2016 at 17:53 Comment(8)
Looks like this is the answer but I am not 100% sure. Leaving it to others to decide if it should be closed as a dupe.Sorgo
@Sorgo That question is about accessing the parameter's value, which is not possible for a good reason (order of evaluation), but I'd expect that its name and type be subject to different rules since that reason does not affect them.Thud
@Thud That is why I did not vote to close. The quote from the standard has Consequently, parameters of a function shall not be used in default argument expressions, even if they are not evaluated. and I am not sure if that applies here or not.Sorgo
@Sorgo int h(int a, int b = sizeof(a)); is used in an example as an error, so I'd say this isn't allowed, after all.Leslie
@Leslie No, that's commented with "Ok"Miley
@Sorgo That is not the same. The Standard forbids use of values in potentially evaluated expression, but decltype(value) is not a potentially evaluated expression.Badlands
@Miley interesting, it is commented with Ok in N4606, but error in 4140.Leslie
I wonder if this is a language change from C++14 to C++17 then. Maybe it was a DR. In C++14 it N3797 it shows using sizeof(a) as being illegal.Sorgo
M
9

According to [basic.scope.pdecl]/1:

The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.

So the parameter is definitely declared at that point. How about using it in decltype? Wording was outdated and inadvertently disallowed it. See 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.

So the quoted paragraph was amended to read

A parameter shall not appear as a potentially-evaluated expression in a default argument.

Since operands of decltype are unevaluated, this is fine now, and GCC is wrong.

Miley answered 9/11, 2016 at 18:5 Comment(4)
This was introduced only in draft, but not in C++14. wg21.cmeerw.net/cwg/issue2082Badlands
@Badlands Yeah, I found that, too, after krzaq's comment.Miley
Is GCC really wrong or does it just need to update how it compiles on c++17/1z? Looks like was forbidden in C++14 so you really cannot fault GCC for that.Sorgo
@Sorgo Yes, you can; core defect resolutions must be implemented promptly, because they concern actual inconsistencies in the language. Also, what point is there in simply postponing all defect resolutions until release of the new standard?Miley

© 2022 - 2024 — McMap. All rights reserved.