When I have two templated function overloads like this:
template<class T>
void foo( T const& )
{
// do something with a const reference
cout << "const reference version";
}
template<class T>
void foo( T const* )
{
// do something with a const pointer
cout << "const pointer version";
}
Why does the compiler choose the first version when instantiated with a non-const pointer type?
int* bar;
foo( bar ); // prints "const reference version"
char const* baz;
foo( baz ); // prints "const pointer version"
The reason is because bar
is a non-const pointer, so int* const&
is actually a better match than int const*
because it doesn't have to add const
to the pointer type.
If bar
were const
qualified then it would be an exact match for the T const*
version.
#include <iostream>
using namespace std;
void foo(int const&) {
cout << "const reference" << endl;
}
void foo(int const*) {
cout << "const pointer" << endl;
}
int main() {
int *hi;
foo (hi); //const pointer
foo((*hi)); //const reference
foo(&(*hi));//const pointer
}
The deal here is references and pointers are different. A pointer is a unique type, where as a reference to a value is no different from the value itself, or rather, an alias to the object. So for example, this version of the code above will not compile.
#include <iostream>
using namespace std;
void foo(int const&) {
cout << "const reference" << endl;
}
void foo(int) {
cout << "hi there" << endl;
}
int main() {
int hi;
foo(hi); //const reference
}
As the declarations of foo are ambiguous. The compiler cannot decide between them.
You can determine what is going on with your template types using typeid
.
#include <iostream>
#include <typeinfo>
using namespace std;
template<class T> void foo( T const& ) {
cout << "const reference version T="<< typeid(T).name()<<endl;
}
template<class T> void foo( T const* ) {
cout << "const pointer version T="<<typeid(T).name()<<endl;
}
int main() {
int* i_ptr=0;
foo(i_ptr);
const int* ci_ptr=0;
foo(ci_ptr);
}
This outputs (note exact output will depend on your compiler)
const reference version T=Pi
const pointer version T=i
Which shows that in the first case T = int*
and the full argument type is int* const&
, and in the second T=int
and the full argument type is int const *
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With