If one defines a new variable in C++, then the name of the variable can be used in the initialization expression, for example:
int x = sizeof(x);
And what about default value of a function argument? Is it allowed there to reference the argument by its name? For example:
void f(int y = sizeof(y)) {}
This function is accepted in Clang, but rejected in GCC with the error:
'y' was not declared in this scope
Demo: https://gcc.godbolt.org/z/YsvYnhjTb
Which compiler is right here?
Once a default value is used for an argument in the function definition, all subsequent arguments to it must have a default value as well. It can also be stated that the default arguments are assigned from right to left.
C has no default parameters.
In C++ programming, we can provide default values for function parameters. If a function with default arguments is called without passing arguments, then the default parameters are used. However, if arguments are passed while calling the function, the default arguments are ignored.
According to the C++17 standard (11.3.6 Default arguments)
9 A default argument is evaluated each time the function is called with no argument for the corresponding parameter. A parameter shall not appear as a potentially-evaluated expression in a default argument. Parameters of a function declared before a default argument are in scope and can hide namespace and class member name
It provides the following example:
int h(int a, int b = sizeof(a)); // OK, unevaluated operand
So, this function declaration
void f(int y = sizeof(y)) {}
is correct because, in this expression sizeof(y)
, y
is not an evaluated operand, based on C++17 8.3.3 Sizeof:
1 The sizeof operator yields the number of bytes in the object representation of its operand. The operand is either an expression, which is an unevaluated operand (Clause 8), or a parenthesized type-id.
and C++17 6.3.2 Point of declaration:
1 The point of declaration for a name is immediately after its complete declarator (Clause 11) and before its initializer (if any), except as noted below.
The code does not appear ill-formed, so Clang is alright.
[basic.scope.pdecl]
1 The point of declaration for a name is immediately after its complete declarator ([dcl.decl]) and before its initializer (if any), except as noted below.
This is the notorious passage that is under discussion. I bring it here just to mention that "except as noted below" doesn't include any mention of default arguments. So y
is declared right before = sizeof(y)
.
The other relevant paragraph is
[dcl.fct.default]
9 A default argument is evaluated each time the function is called with no argument for the corresponding parameter. A parameter shall not appear as a potentially-evaluated expression in a default argument. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names.
sizeof(y)
is not potentially evaluated, so this is also fine.
Seeing as the first paragraph makes y
available as a name, and it's used in a way that is not illegal, must be some quirk of GCC that rejects the code.
Though personally, I don't see it as a great loss. This is not the most practical bit of code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With