Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 286
stillanoob Avatar asked Jun 20 '16 01:06

stillanoob


2 Answers

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)
like image 93
paxdiablo Avatar answered Oct 18 '22 12:10

paxdiablo


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.”

like image 28
ThomasMcLeod Avatar answered Oct 18 '22 12:10

ThomasMcLeod