The following code compiles cleanly with GCC:
void func(int arg1, decltype(arg1) arg2)
{
(void)arg2;
}
int main(){}
I used this command to compile:
g++ -std=c++14 test.cpp -o test -pedantic-errors -Wall -Wextra
But such usage of a parameter in the middle of function declaration seems weird. Is it actually valid in standard C++, or is it a GCC extension?
This is fine. The ISO C++11 Standard even gives your situation as an example.
First the parameter is in scope:
3.3.3 Block scope [ basic.scope.local ]
2 The potential scope of a function parameter name (including one appearing in a lambda-declarator) or of
a function-local predefined variable in a function definition (8.4) begins at its point of declaration.
An example can be found here:
8.3.5 Functions [ dcl.fct ]
5 [ Note: This transformation does not affect the types of the parameters. For example, int(*)(const int p, decltype(p)*) and int(*)(int, const int*) are identical types. — end note ]
Yes, it's legal. It's basically just a question of scope. From [basic.scope.block]:
The potential scope of a function parameter name (including one appearing in a lambda-declarator) or of a function-local predefined variable in a function definition (8.4) begins at its point of declaration.
The scope of arg1 begins here:
void func(int arg1, decltype(arg1) arg2)
------------------^
Hence arg1 is in scope for the declaration of arg2. I think that's sufficient.
The rule for disallowing defaulting arg2 to arg1 is separate -- which to me suggests that arg1 was in scope and had to be explicitly disallowed.
If we look in N3979 [dcl.fct.default] we have
Default arguments are evaluated each time the function is called. 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. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names. [ Example:
int a;
int f(int a, int b = a); // error: parameter a
// used as default argument
typedef int I;
int g(float I, int b = I(2)); // error: parameter I found
int h(int a, int b = sizeof(a)); // error, parameter a used
// in default argument
[...]
Emphasis mine
So in the example a is known when we get to b and it hides the a from the calling scope. This leads me to believe each function parameter is known before each subsequent parameter. This means you should be able to use its type. You cannot use its value - as the order of evaluation of the values is unspecified - but the names should be introduced in order from left to right.
Related
I have a little toy program:
static int value = 0;
int function(int &value=value) {
return value;
}
int main() {
function();
}
Compiling with g++ 7.2:
g++ -std=c++11 -Wall -Wextra test.cc -o test
No problem.
Compiling with clang++-3.9:
clang++-3.9 -std=c++11 -Wall -Wextra test.cc -o test
test.cc:3:25: error: default argument references parameter 'value'
int function(int &value=value) {
^~~~~
test.cc:8:5: error: no matching function for call to 'function'
function();
^~~~~~~~
test.cc:3:5: note: candidate function not viable: requires single argument 'value', but no arguments were provided
int function(int &value=value) {
^
2 errors generated.
Kaboom. Who's right?
I think clang is correct. From basic.scope.pdecl:
The point of declaration for a name is immediately after its complete declarator (Clause [dcl.decl]) and before its initializer (if any), except as noted below. [ Example:
int x = 12;{ int x = x; }
Here the second x is initialized with its own (indeterminate) value. — end example ]
Also, from dcl.fct.default:
Default arguments are evaluated each time the function is called. 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. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names
Since the OP tagged the question as c++11 I checked that version of the standard and in [basic.lookup.unqual] sub-clause 11 it states explicitly that:
During the lookup for a name used as a default argument (8.3.6) in a
function parameter-declaration-clause or used in the expression of a
mem-initializer for a constructor (12.6.2), the function parameter
names are visible and hide the names of entities declared in the
block, class or namespace scopes containing the function declaration.
Thus, clang is correct.
Clang is correct here. First a function's parameter scope is defined as:
A function parameter (including one appearing in a lambda-declarator) or function-local predefined variable ([dcl.fct.def]) has function parameter scope. The potential scope of a parameter or function-local predefined variable begins at its point of declaration.[...]
and the point of declaration is defined as
The point of declaration for a name is immediately after its complete declarator and before its initializer (if any), except as noted below. [ Example:
unsigned char x = 12;
{ unsigned char x = x; }
Here the second x is initialized with its own (indeterminate) value. — end example ]
So value should be the value you just declared and not the one from the global space
How can I receive in a function definition when the one of the parameter in function call is void?
The scenario is that one of my projects, in a function call one of the parameters is void. That section I could not change.
I can change only the function declaration or the function definition, but I still confused what I need to change.
Please help
Below code is not a executable one:
for ex:
#include <stdio.h>
void test(void, int a) {
printf("%d", a);
}
int main() {
test(void, 32);
}
You can't. That is not valid C:
<source>:2:11: error: 'void' must be the only parameter
2 | void test(void,int a)
| ^~~~
Same goes for C++:
<source>:2:11: error: invalid use of type 'void' in parameter declaration
2 | void test(void,int a)
| ^~~~
The only valid use of void as parameter is on it's own, as in:
int bar();
int foo(void);
In C this means the function bar takes an undetermined number of arguments while foo does not take any arguments. In C++ both are equivalent.
void is an incomplete type and cannot be used as the parameter of a function(in both C and C++) with the exception that if void is the only parameter of that function. This can be seen from the following quoted statements.
C++
From function's documentation:
Parameter list determines the arguments that can be specified when the function is called. It is a comma-separated list of parameter declarations, each of which has the following syntax:
5 Indicates that the function takes no parameters, it is the exact synonym for an empty parameter list: int f(void); and int f(); declare the same function. Note that the type void (possibly cv-qualified) cannot be used in a parameter list otherwise: int f(void, int); and int f(const void); are errors (although derived types, such as void* can be used). In a template, only non-dependent void type can be used (a function taking a single parameter of type T does not become a no-parameter function if instantiated with T = void).
Note also that there is a semantic difference(between C++ & C) in case void is used as a parameter of a function and is the only parameter as shown in the following example:
int func(void); //declaration of func that takes no parameter and has the return type of void
int foo(); //declaration of foo that takes no parameter and has the return type of void
C
From function declaration's documentation:
parameters cannot have type void (but can have type pointer to void). The special parameter list that consists entirely of the keyword void is used to declare functions that take no parameters.
int f(void); // OK
int g(void x); // Error
Unlike in C++ and function definitions (since C23), the declarators f() and f(void) have different meaning: the declarator f(void) is a new-style (prototype) declarator that declares a function that takes no parameters. The declarator f() is a declarator that declares a function that takes unspecified number of parameters (unless used in a function definition)
As shown highlighted in attached snapshot,starting line of main function,i know that it is starting point of main function but what is the proper term for it?can we call it function declaration line?
I don't know about C, but here are some snippets from the C++23 draft:
dcl.fct.def/3
Example 1: A simple example of a complete function definition is
int max(int a, int b, int c) {
int m = (a > b) ? a : b;
return (m > c) ? m : c;
}
Here int is the decl-specifier-seq; max(int a, int b, int c) is the declarator; { /* ... */ } is the function-body. — end example]
So, in int main() we get that int is the decl-specifier-seq and main() is the declarator.
We also have another example (sorry for only finding examples) dcl.fct/9:
[Example 5: The declaration
int fseek(FILE*, long, int);
declares a function taking three arguments of the specified types, and returning int ([dcl.type]). — end example]
(while not formal), I deduce that the combination of the decl-specifier-seq and the declarator makes the int main() part a declaration.
This line
int main()
in the function definition (that is at the same time a function declaration) is called the function declarator that has the return type (type specifier) int.
That is this code snippet in whole
int main()
{
//...
}
is a function declaration that introduce the identifier main in the file scope.
Pay attention to that according to the C Standard the function declarator of main that does not accept arguments shall be declared like
int main( void )
There are two terms in C and C++ that share a common usage, and unfortunately often gets confused with each other. The terms are declaration and definition.
A declaration is telling the compiler that something (a "name") exists, somewhere in the program. A definition is the implementation of the thing that was declared.
For functions, you can have a declaration and definition at the same time.
For example lets say your program have a function named foo, taking one int argument and returning a int value. It can be declared as:
int foo(int arg);
This declaration of the function is also known as declaring the prototype of the function. You need to have this declaration before you call the function, or the compiler won't know that it exist. After the declaration it's possible to call the function, the compiler don't need to see the full implementation of the function, only the declaration.
Then we have the definition, where we implement the function:
int foo(int arg)
{
return arg * 2;
}
Now lets take another function bar which takes no arguments and returns no value. It has no previous declaration, only a definition:
void bar(void)
{
// Does something here...
}
But because there's no existing declaration before the definition, the definition is also is the declaration.
Also note that there is a big difference between C and C++ when it comes to function declarations.
In C a function taking no arguments must use the argument type void. Not specifying any arguments:
void some_function();
actually declares the function some_function as taking an indeterminate number of arguments of indeterminate type. The C compiler will then fill in the missing arguments details when the first call is made, or when it finds another declaration (or definition) that specifies the arguments.
In C++ such a declaration declares the function as taking no arguments.
This is only one difference between C and C++, and the reason why many of us here don't like questions being tabbed with both languages, or the term "C/C++".
In simple terms, function declaration means are just declaring the function name, its arguments and its return type.
e.g.
int foo(int x, int y); ==> Function declaration ends with semicolon ;
Function definition means you are actually defining the functionality.
e.g.
int foo(int x, int y){
return x+y;
} ==> Function definition enclosed within curly braces { }
And the given main() function is function definition.
In general terms, for conventional purpose may be you can call the first line of a function definition as "function header".
And the entire code within the curly braces { } of the function definition as "function body".
Consider the following constructor:
class MyClass {
MyClass(unsigned int dimension, std::vector vector=unitaryVector(dimension));
};
where unitaryVector(d) is a function that returns a random std::vector in d dimensions.
This gives the following compiler error:
error: default argument references parameter 'dimension'
MyClass(unsigned int dimension, std::vector vector=unitaryVector(dimension));
Why isn't this idiom valid in C++11? It seems to be pretty obvious: if vector argument is provided, init vector as a copy of the argument, otherwise, call the function and init it as a copy of the return value. Why can't a compiler understand this?
The C++ standard forbids it.
dcl.fct.default
9 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.
[ Example:
int a;
int f(int a, int b = a); // error: parameter a
// used as default argument
typedef int I;
int g(float I, int b = I(2)); // error: parameter I found
int h(int a, int b = sizeof(a)); // OK, unevaluated operand
— end example ]
Note that default arguments are replaced at the call site if not provided
Intro.execution (emphasis mine)
11: [ Note: The evaluation of a full-expression can include the evaluation of subexpressions that are not lexically part of the
full-expression. For example, subexpressions involved in evaluating
default arguments ([dcl.fct.default]) are considered to be created
in the expression that calls the function, not the expression that
defines the default argument. — end note ]
You can simply overload the constructor and delegate it:
class MyClass {
explicit MyClass(unsigned int dimension)
: MyClass(dimension, unitaryVector(dimension)) //delegation
{ }
MyClass(unsigned int dimension, std::vector vector);
};
Footnote: Its a good thing to make single argument constructors explicit
One alternative is to use
class MyClass {
MyClass(unsigned int dimension, std::vector const& vector) :
dimension(dimension), vector(vector) {}
MyClass(unsigned int dimension) :
MyClass(dimension, unitaryVector(dimension)) {}
};
(this of course when you want to store dimension and vector in the class).
Because the default argument must be complete in itself so that compiler can simply replace it if not provided by call. The (local) variable dimension isn't created yet and you are trying to use it, and hence the error. This would work, however:
int _def_dim=10;
class MyClass {
MyClass(unsigned int dimension, std::vector vector=unitaryVector(_def_dim));
};
I am not sure what standard says, but for compiler implementation is would be tricky to handle such corner cases.
EDIT (for completeness), grabbed from this answer:
Default arguments are evaluated each time the function is called. The
order of evaluation of function arguments is unspecified.
Consequently, parameters of a function shall not be used in default
argument expressions, even if they are not evaluated.
I was writing a function foo() which takes 2 const char*s as arguments, pBegin and pEnd. foo() is passed a null terminated string. By default pEnd points to \0 (last character) of the string.
void foo (const char *pBegin,
const char *pEnd = strchr(pBegin, 0)) // <--- Error
{
...
}
However, I get an error at above line as:
error: local variable ‘pBegin’ may not appear in this context
Why compiler doesn't allow such operation ? What's the potential problem ?
The standard not only explicitly disallows the use of other parameters in a default argument expression, but also explains why and gives an example:
ISO/IEC 14882:2003(E) - 8.3.6 Default arguments [dcl.fct.default]
9. Default arguments are evaluated each time the function is called.
The order of evaluation of function arguments is unspecified.
Consequently, parameters of a function shall not be used in default
argument expressions, even if they are not evaluated. Parameters of a
function declared before a default argument expression are in scope
and can hide namespace and class member names. [Example:
int a;
int f(int a, int b = a); // error: parameter a
// used as default argument
typedef int I;
int g(float I, int b = I(2)); // error: parameter I found
int h(int a, int b = sizeof(a)); // error, parameter a used
// in default argument
—end example] ...
The language still offers a way to do what you want - use overloaded functions:
void foo (const char *pBegin, const char *pEnd)
{
//...
}
void foo (const char *pBegin)
{ foo(pBegin, strchr(pBegin, 0)); }
When the function is called the default arguments are evaluated, but the order they are evaluated is not defined by the C++ standard. That means that you can't reference other parameters in a default argument because they may not have a known value yet.
You can't use a local variable in a default argument value.
Quote from here:
The standard tells us that the default argument is simply an expression.
There are some things that are no allowed (using local variables, using
the keyword 'this') but pretty much anything else can serve as a default
argument.