Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function default argument value depending on argument name in C++

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?

like image 548
Fedor Avatar asked Oct 06 '21 07:10

Fedor


People also ask

Can a function argument have default value?

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.

Can C functions have default arguments?

C has no default parameters.

How can we pass default arguments to a function?

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.


2 Answers

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.

like image 148
Vlad from Moscow Avatar answered Oct 17 '22 10:10

Vlad from Moscow


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.

like image 26
StoryTeller - Unslander Monica Avatar answered Oct 17 '22 11:10

StoryTeller - Unslander Monica