46

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?

2

2 Answers 2

35

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.

Sign up to request clarification or add additional context in comments.

2 Comments

But then how do you explain the error given by gcc? Or is it a bug in gcc?
@KshitijJoshi It is a bug of the compiler.
9

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.

3 Comments

Note that in C++11, there is a different formulation: "parameters of a function shall not be used in a default argument, even if they are not evaluated". Link: timsong-cpp.github.io/cppwp/n3337/dcl.fct.default#9.
@DanielLangr - Interesting. May be a left over in g++'s frontend. It does accept the standard's examples, though.
I think they should have just removed the restriction, and let the compiler order the defaulted arguments as needed for potentially-evaluated use of other arguments. Would have simplified use at least.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.