简体   繁体   中英

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"

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM