Reputation: 1379
Consider the following code snippets:
void foo(const int i) // First foo
{
std::cout << "First " << i << endl;
}
void foo(int i) // Second foo
{
std::cout << "Second " << i << endl;
}
int main()
{
int i = 5;
foo(i);
}
Compilation Error:
redefinition of 'void foo(int)'
Since const
s can be initialized with non-const
objects, the above behaviour seems reasonable. Now consider this:
void foo_ptr(const int* p) // First foo_ptr
{
std::cout << "First " << *p << endl;
}
void foo_ptr(int* p) // Second foo_ptr
{
std::cout << "Second " << *p << endl;
}
int main()
{
int i = 5;
foo_ptr(&i); // Second foo_ptr gets called; prints 'Second 5'
}
As it might be clear, my question is - If the two definitions of foo
in the first case are considered the same then why it is not so for foo_ptr
in the second case? Or in other words, why const
is ignored in the first case and not so in the second one?
Upvotes: 5
Views: 1286
Reputation: 7769
During overload resolution, const
and volatile
specifies on parameters are significant except when they occur at the outermost level of the of the parameter type specification. From the C++ standard, § 13.1.3.4:
Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function is being declared, defined, or called. [ Example:
typedef const int cInt;
int f (int);
int f (const int); // redeclaration of f(int)
int f (int) { /* ... */ } // definition of f(int)
int f (cInt) { /* ... */ } // error: redefinition of f(int)
—end example ] Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations. In particular, for any type T, “pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.”
Upvotes: 2
Reputation: 881153
const int* p
is not a constant pointer to an integer, it's a pointer to a constant integer (i.e., [const int] * p
rather than const [int * p]
). This is why you sometimes see code like:
const int * const p;
which may seem redundant to the uninitiated but is really not - p
in that case is a pointer you're not allowed to change, which points to an integer you're also not allowed to change.
Hence the two functions you have in your second case are considered different in terms of the parameters accepted. That's also why you're calling the second function, since i
is most definitely not a const
integer.
In other words, while const
-ing a parameter does not change it in terms of the function signature, that's not what you're doing here. Changing a parameter from "pointer to int" to "pointer to const int" does affect the signature.
The equivalent case to your first code snippet would be providing both of:
void foo_ptr (int * const p)
void foo_ptr (int * p)
Upvotes: 5
Reputation: 172884
why
const
is ignored in the first case and not so in the second one?
In the 1st case, const
is qualified for the parameter itself, while in the 2nd case, const
is qualified for the pointee, not the pointer itself. Const pointer and pointer to const are not the same thing.
In the 2nd case, pointer to const and pointer to non-const are different and acceptable for overloading. If you make the pointer itself const
, i.e. int* const p
vs int* p
, you'll get the same result as the 1st case.
Upvotes: 0
Reputation: 118292
Because when you declare
void foo(const int n)
{
}
All that the const
modifier does is prevent n
from being modified inside the foo()
function. The parameter to this foo()
function is still an int
. The const
modifier does not modify the parameter's type. So both
void foo(int n)
and
void foo(const int n)
are functions that take an int
parameter. The only difference between them is that the second one cannot modify it's parameter, while the first one can modify it, like any other non-const
variable inside the function.
However, there is a difference between
void foo(const int *p)
and
void foo(int *p)
One is a pointer to a const
integer, the other one is a pointer to a mutable integer. They are different types.
Bonus answer:
Both
void foo(int *p)
and
void foo(int * const p)
have the same parameter type. Both functions' parameter is a pointer to an int
. Except that the second one's parameter is const
value, and the function cannot modify it.
Confused yet?
Upvotes: 0