idefixs
idefixs

Reputation: 712

function template overloading: const* vs. const&

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"

Upvotes: 8

Views: 767

Answers (4)

Michael Anderson
Michael Anderson

Reputation: 73520

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

Upvotes: 1

MobA11y
MobA11y

Reputation: 18880

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

Upvotes: 3

UmNyobe
UmNyobe

Reputation: 22910

template<class T> void foo( T const* ) requires a const pointer on T. Well if it was the only declaration you had, there will be a compilation error as you are trying to pass a non const pointer as argument.

With template<class T> void foo( T const& ) the type T inferred is int* which is given by reference to the function.

Upvotes: 0

Mark B
Mark B

Reputation: 96281

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.

Upvotes: 5

Related Questions