1.
int Add (int a, int b = 3);
int Add (int a, int b)
{
}
2.
int Add (int a, int b);
int Add (int a, int b = 3)
{
}
Both work; which is the standard way and why?
If you put the declaration in a header file, and the definition in a separate .cpp file, and #include the header from a different .cpp file, you will be able to see the difference.
Specifically, suppose:
lib.h
int Add(int a, int b);
lib.cpp
int Add(int a, int b = 3) {
...
}
test.cpp
#include "lib.h"
int main() {
Add(4);
}
The compilation of test.cpp will not see the default parameter declaration, and will fail with an error.
For this reason, the default parameter definition is usually specified in the function declaration:
lib.h
int Add(int a, int b = 3);
In C++ the requirements imposed on default arguments with regard to their location in parameter list are as follows:
Default argument for a given parameter has to be specified no more than once. Specifying it more than once (even with the same default value) is illegal.
Parameters with default arguments have to form a contiguous group at the end of the parameter list.
Now, keeping that in mind, in C++ you are allowed to "grow" the set of parameters that have default arguments from one declaration of the function to the next, as long as the above requirements are continuously satisfied.
For example, you can declare a function with no default arguments
void foo(int a, int b);
In order to call that function after such declaration you'll have to specify both arguments explicitly.
Later (further down) in the same translation unit, you can re-declare it again, but this time with one default argument
void foo(int a, int b = 5);
and from this point on you can call it with just one explicit argument.
Further down you can re-declare it yet again adding one more default argument
void foo(int a = 1, int b);
and from this point on you can call it with no explicit arguments.
The full example might look as follows
void foo(int a, int b);
int main()
{
foo(2, 3);
void foo(int a, int b = 5); // redeclare
foo(8); // OK, calls `foo(8, 5)`
void foo(int a = 1, int b); // redeclare again
foo(); // OK, calls `foo(1, 5)`
}
void foo(int a, int b)
{
// ...
}
As for the code in your question, both variants are perfectly valid, but they mean different things. The first variant declares a default argument for the second parameter right away. The second variant initially declares your function with no default arguments and then adds one for the second parameter.
The net effect of both of your declarations (i.e. the way it is seen by the code that follows the second declaration) is exactly the same: the function has default argument for its second parameter. However, if you manage to squeeze some code between the first and the second declarations, these two variants will behave differently. In the second variant the function has no default arguments between the declarations, so you'll have to specify both arguments explicitly.
The first way would be preferred to the second.
This is because the header file will show that the parameter is optional and what its default value will be. Additionally, this will ensure that the default value will be the same, no matter the implementation of the corresponding .cpp file.
In the second way, there is no guarantee of a default value for the second parameter. The default value could change, depending on how the corresponding .cpp file is implemented.
Default arguments must be specified with the first occurrence of the function name—typically, in the function prototype. If the function prototype is omitted because the function definition also serves as the prototype, then the default arguments should be specified in the function header.
On thing to remember here is that the default param must be the last param in the function definition.
Following code will not compile:
void fun(int first, int second = 10, int third);
Following code will compile:
void fun(int first, int second, int third = 10);
Related
1.
int Add (int a, int b = 3);
int Add (int a, int b)
{
}
2.
int Add (int a, int b);
int Add (int a, int b = 3)
{
}
Both work; which is the standard way and why?
If you put the declaration in a header file, and the definition in a separate .cpp file, and #include the header from a different .cpp file, you will be able to see the difference.
Specifically, suppose:
lib.h
int Add(int a, int b);
lib.cpp
int Add(int a, int b = 3) {
...
}
test.cpp
#include "lib.h"
int main() {
Add(4);
}
The compilation of test.cpp will not see the default parameter declaration, and will fail with an error.
For this reason, the default parameter definition is usually specified in the function declaration:
lib.h
int Add(int a, int b = 3);
In C++ the requirements imposed on default arguments with regard to their location in parameter list are as follows:
Default argument for a given parameter has to be specified no more than once. Specifying it more than once (even with the same default value) is illegal.
Parameters with default arguments have to form a contiguous group at the end of the parameter list.
Now, keeping that in mind, in C++ you are allowed to "grow" the set of parameters that have default arguments from one declaration of the function to the next, as long as the above requirements are continuously satisfied.
For example, you can declare a function with no default arguments
void foo(int a, int b);
In order to call that function after such declaration you'll have to specify both arguments explicitly.
Later (further down) in the same translation unit, you can re-declare it again, but this time with one default argument
void foo(int a, int b = 5);
and from this point on you can call it with just one explicit argument.
Further down you can re-declare it yet again adding one more default argument
void foo(int a = 1, int b);
and from this point on you can call it with no explicit arguments.
The full example might look as follows
void foo(int a, int b);
int main()
{
foo(2, 3);
void foo(int a, int b = 5); // redeclare
foo(8); // OK, calls `foo(8, 5)`
void foo(int a = 1, int b); // redeclare again
foo(); // OK, calls `foo(1, 5)`
}
void foo(int a, int b)
{
// ...
}
As for the code in your question, both variants are perfectly valid, but they mean different things. The first variant declares a default argument for the second parameter right away. The second variant initially declares your function with no default arguments and then adds one for the second parameter.
The net effect of both of your declarations (i.e. the way it is seen by the code that follows the second declaration) is exactly the same: the function has default argument for its second parameter. However, if you manage to squeeze some code between the first and the second declarations, these two variants will behave differently. In the second variant the function has no default arguments between the declarations, so you'll have to specify both arguments explicitly.
The first way would be preferred to the second.
This is because the header file will show that the parameter is optional and what its default value will be. Additionally, this will ensure that the default value will be the same, no matter the implementation of the corresponding .cpp file.
In the second way, there is no guarantee of a default value for the second parameter. The default value could change, depending on how the corresponding .cpp file is implemented.
Default arguments must be specified with the first occurrence of the function name—typically, in the function prototype. If the function prototype is omitted because the function definition also serves as the prototype, then the default arguments should be specified in the function header.
On thing to remember here is that the default param must be the last param in the function definition.
Following code will not compile:
void fun(int first, int second = 10, int third);
Following code will compile:
void fun(int first, int second, int third = 10);
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".
I am a bit puzzled with the following behavior. I pass a function with two parameter, one having a default value, as a template parameter and call the function with one argument. Why does it fail to compile? And, what is the solution/workaround?
#include <iostream>
using namespace std;
template<typename Function>
void eval(Function function) {
function(10);
}
void sum(int i, int j = 0) {
cout << "Sum is " << i + j;
}
int main() {
sum(10); // OK, of course :)
eval(sum); // Error!
}
Note that this question is not about calling a templated function with default parameter.
The error message:
prog.cpp: In instantiation of 'void eval(Function) [with Function = void (*)(int, int)]':
prog.cpp:15:10: required from here
prog.cpp:6:10: error: too few arguments to function
function(10);
^
That's because the optional parameter is part of function declaration. When you call using a function pointer, essentially all the compiler knows is the type of the function pointer. So this line function(10) roughly translates to:
void (*)(int, int) sm = function; // the equivalent happens at the type deduction step
sm(10); // whoops, where is the second int
The compiler will need the second argument because it has no way of knowing whether sm is pointing to sum which has a default argument, or some other void foo(int a, int b) which doesn't have a default argument.
This is why function pointers are weak. You got two good answers of why this doesn't work - the function template doesn't know your function has a defaulted argument.
The solution is to not pass a function pointer - pass in a function object. In this case, you can handwrite a lambda:
eval([](int i){ return sum(i); });
which seems like a really annoyingly verbose way of basically just writing sum in a way that actually works. But this sort of thing comes up periodically (what if sum were an overloaded name?) so it's handy to just have a lambdafying macro around (C++14 required):
#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(auto) { \
return func(std::forward<decltype(args)>(args)...); }
so you can write:
eval(AS_LAMBDA(sum));
That will work with defaulted arguments, overloaded names, and even work to bind member functions:
struct X {
int i;
int add(int j) { return i + j; }
};
X x{42};
eval(AS_LAMBDA(x.add));
When you call sum:
sum(10);
compiler translates it to:
sum(10, 0);
There is no error, as arguments are matched. For the compiler there exist no sum taking one argument. You can say a pre-compiler doing the magic of passing 0 to second argument to sum. With templates this magical pre-compiler doesn't exist, and the actual compiler matches sum with two strictly two arguments, which it doesn't find, and hence the error.
Just like
void foo(int);
void foo(float);
will fail to compile with foo(10.2); where argument double can be changed to either float or int. The compiler will not assume float for you. Similarly, compiler will not try to find best match of sum just for the sake of successful compilation.
I recently found out that you can add and remove cv-qualifier from value arguments in a function declaration and it's implementation. For instance:
F.h
f(const int i);
F.cpp
f(int i) { i++; }
test.cpp
#include "F.h"
f(0);
The f(int i) implementation will be called. Since its a copy by value, I see no problems with the code compiling. But can anyone imagine a case, where it's somehow useful to add the const to the declaration as done above? Why is it possible at all? Maybe someone can give a more useful application?
Top-level CV qualifiers on function arguments are ignored, i.e. they are not part of the function signature. Rather, if you will, they are part of the implementation of the function, since they qualify the local variables corresponding to the formal function parameters. Therefore, if it pleases you, you may qualify function parameters in the function definition:
int power(int val, int n, int base);
int power(int val, int n, const int base)
{
while (n --> 0) val *= base;
return val;
}
Some people find it offensive if the definition has different-looking function parameters from the declaration, though. It's a matter of taste and style. The benefits of qualifying the arguments are probably small, though there is some value for the implementation in documenting that you don't plan to change a variable.
Some people like to state in their definition that they are not going to change a parameter even though it is only visible locally. For example:
void f(int);
void f(int const);
void f(int const x) {
x = 3; // ERROR!
}
The definition is the function which was just declared, i.e., there is no change on the signature (well, unless you happen to use Sun's CC which actually takes the const into account for the mangled name but that's just an error). All three signatures declare exactly the same function and the const only affects the body of the definition if it is used in the definition's declaration.
What does the C++ compiler do when coming ambiguous default parameters? For example, let's say there was a function such as:
void function(int a = 0, float b = 3.1);
void function(int a, float b =1.1, int c = 0);
Is the above considered ambiguous? If not, what does the compiler do (how is the function matched exactly) when calling something like function1(10) ?
Thanks!
The following is fine
void function(int a = 0, float b = 3.1);
void function(int a, float b =1.1, int c = 0);
And the following is fine too
function(); // calls first function
But the following is ambiguous
function(1); // second and first match equally well
For overload resolution (the process that tells what function to call), parameters that have not passed explicit arguments and that make use of default arguments are ignored. So the compiler really sees two functions both having one int parameter for the above call and can't decide.
The following is ill-formed though
void function(int a = 0, float b = 3.1);
void function(int a, float b =1.1);
While for the code in your question you declare two functions (because both declarations have different number of parameters), in this example you only declare one function. But the second declaration of it repeats a default argument for a parameter (and even with a different value, but that doesn't matter anymore). This is not allowed. Note that the following is fine
void function(int a, float b = 3.1);
void function(int a = 0, float b);
The set of default arguments for declarations that appear in the same scope for the same function are merged, and only for those that appear in the same scope. So the following is valid
void function(int a = 0, float b = 3.1);
void function1() {
void function(int a, float b = 1.1);
function(0);
}
This calls the function with 1.1 passed for b.
If they have different names (as in your example), there's no ambiguity. If they have the same name (so it's an attempt at an overload), the compiler will complain.
Though it turns out you can redefine the default arguments to a function in a different scope (this is news to me...) - but in the same scope, you can't redefine default arguments even to the same value. from 8.3.6/4 "Default arguments":
For non-template functions, default
arguments can be added in later
declarations of a function in the same
scope. Declarations in different
scopes have completely distinct sets
of default arguments. That is,
declarations in inner scopes do not
acquire default arguments from
declarations in outer scopes, and vice
versa. In a given function
declaration, all parameters subsequent
to a parameter with a default argument
shall have default arguments supplied
in this or previous declarations. A
default argument shall not be
redefined by a later declaration (not
even to the same value).
Ambiguous? You have two completely independent different functions: function1 and function2. Even the number of parameters in each function is different. There's no ambiguity here whatsoever. When you ask the compiler to call function1(10) it calls function1(10, 3.1). function2 doesn't even come into the picture.
If it were the same function, then the issue of ambiguity would not arise simply because it is illegal in C++ to specify a default argument for the same parameter more than once (within the same translation unit). Even of you specify the same default argument value the second time, the program is ill-formed
void foo(int a = 5);
void foo(int a = 5); // <- ERROR
What one can do though is to specify a different set of default arguments for the same function in different translation units. But that does not create any ambiguity because the compiler can see only one translation unit. The compiler simply will never know of any potential "ambiguity" is that case.
Furthermore, the answer to any question starting with, "What does the C++ compiler do...," is always going to be, "Depends on which compiler you're talking about."