stillanoob
stillanoob

Reputation: 1379

Function Overloading in C++ (const pointers)

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 consts 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

Answers (4)

ThomasMcLeod
ThomasMcLeod

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

paxdiablo
paxdiablo

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

songyuanyao
songyuanyao

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

Sam Varshavchik
Sam Varshavchik

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

Related Questions