functions with const arguments Overloading ( Follow up)
In C++, the function signatures
int Test::foo (const int a) const
and
int Test::foo (int a) const
are considered to be complete identical.
The reason that the const
on the parameter is disregarded is because it can not affect the caller in any way. As the parameter is passed by value, a copy is made of the value provided by the caller. To the caller, it does not matter in any way if the called function can change that copy or not.
For this reason, C++ ignores a top-level const
-qualification on function parameters (top-level const
can not occur if passing a reference), and goes even as far that int foo(int);
is considered a correct prototype for the function
int foo(const int)
{
/* ... */
}
In short, it is impossible in C++ to overload a function on the constness of (value) function parameters.
To get the output you want, you could consider using a non-const reference parameter for your non-const overload.
const Function Overloading
const char*
and char *
are actually not the same. The later allow for modifying the pointed char
, while the first one will prevent that.
Also note that if those were class methods, void display()
and void display() const
would also be valid overloads. The later would imply that the method must not change the object's state.
Consider this code:
void display(char *s)
{
std::cout << "Display" << std::endl;
}
void display(const char *s)
{
std::cout << "Display with const" << std::endl;
}
int main()
{
char *str = strdup("boap");
const char *str2 = "toto";
/* It is a string literral "bound" as a char *.
Compiler will issue warning, but it still compiles.
Avoid to do that, it's just an exemple */
char *not_safe = "not_safe";
display("llama");
display(str2);
display(str);
display(not_safe);
}
This will print Display with const
twice, and then twice Display
. See there.
Now, let's see why:
"llama"
is a string literal, and then is resolved as aconst char *
.str2
is a pointer to a string literal. Since its type isconst char*
, this also revolves to theconst
overload.not_safe
is also a pointer to a string literal. However, its type ischar *
: this is not correct. The memory it points to is read-only, and trying to modifies it will result in a crash. However, the type of the variable is stillchar *
, so this resolve to the non-const
overload.str
is achar *
pointer, and the string it points to is not read-only. Modifying its content is valid, and since its type ischar *
, it will resolve to the non-const overload.
Why are const qualifiers in function arguments used for overloading resolution?
I thought the const was only there to tell the compiler that the object being
passed is not changed and in the second case it is copied anyway
You are correct. Because in the second case it's copied anyway, and so the const
makes no difference to the caller, the standard defines that void f(const int x)
and void f(int x)
have the same signature. Hence they collide, you're trying to define the same function twice.
Because in the first case it isn't copied anyway, void f(const int &x)
and void f(int &x)
have different signatures. Hence they overload.
In your first case, it's forbidden to call the int&
version of f
with x2
as argument, because that would create a non-const reference to a const object without any explicit cast in sight. Doing that defeats the purpose of the const system (which is that if you want to break const-safety, you have to do so explicitly with a cast). So it makes sense to have const- and non-const overloads of functions with reference parameters.
In your second case, there's no relation between the const-ness of the source of a copy, and the const-ness of the destination. You can initialize a const variable from a non-const one, or a non-const one from a const one. This causes no problems and doesn't break const-safety. That's why the standard helpfully makes this clear by defining that your two "different" versions of f
are actually the same function.
How does overloading of const and non-const functions work?
In the example you gave:
vector<int>::const_iterator it = myvector.begin();
if myvector
isn't const the non-const version of begin()
will be called and you will be relying on an implicit conversion from iterator to const_iterator.
Overloading with “const” at end of function declaration
Member functions have an implicit argument which is the instance of the class itself. So you can think your functions as really looking like:
// 1) compile-error as const-qualifications on return doesn't distinguish
// the functions - you cannot overload on return type
int begin(Test& );
const int begin(Test& );
// 2)
int begin(Test& );
const int begin(const Test& );
// 3)
int begin(Test& );
int begin(const Test& );
With the 2nd and 3rd cases, the const
-qualification on the function is equivalent to that implicit argument being a reference-to-const. So when you have something like:
Test{}.begin();
That calls begin()
using a reference to non-const Test
as the implicit first argument. Both overloads of begin()
are viable, both require no conversions, so the least cv-qualified reference is preferred, which is the non-const
-qualified function.
Instead, when you have:
(const Test{}).begin();
we're calling begin()
with a reference to const Test
. So the non-const
-qualified function is not a viable candidate (you cannot pass a const-ref to a function expecting a non-const-ref), so the best viable candidate is the only viable candidate: int begin() const
.
Related Topics
Rand() % 14 Only Generates the Values 6 or 13
How to Get Available Memory C++/G++
Trailing Return Type Using Decltype With a Variadic Template Function
Winmain and Main() in C++ (Extended)
How Does This Template Magic Determine Array Parameter Size
Arrays VS Vectors: Introductory Similarities and Differences
Alternative Virtual Function Calls Implementations
Sort List Using Stl Sort Function
Error Lnk2005, Already Defined
How to Get the Argument Types of a Function Pointer in a Variadic Template Class
Increasing Accuracy of Solution of Transcendental Equation
Why Can't I Have a Non-Integral Static Const Member in a Class
How to Select a Range of Values in a Switch Statement
Why Do Std::Shared_Ptr≪Void≫ Work
Template Specialization of Particular Members
What Is the Logic Behind the "Using" Keyword in C++