Question

I have the following code:

void A(const int*)
{
    cout << "const int*" << endl;
}

void A(const int&)
{
    cout << "const int&" << endl;
}

template <typename T>
void B(const T*)
{
    cout << "const T*" << endl;
}

template <typename T>
void B(const T&)
{
    cout << "const T&" << endl;
}

int main()
{
    int* a = nullptr;
    A(a);            //output: const int*

    int* b = nullptr;
    B(b);            //output: const T&

    return 0;
}

A(a) is invoking the function A(const int*)
B(b) is invoking the template function B(const T&)

I am not surprised from the template behaviour because of the way overload resolution works. But I cannot explain why the non-templated functions return the opposite result (which is kinda the more intuitive).

Is it because with the non-templated functions there is no need for the type to be deduced and is considered exact match (adding const-ness is permited?) ?

I am not an expert with meta programming and the things that the compiler is doing (like overload resolution) and that's why I am a bit confused.

Was it helpful?

Solution

In the call to the non-template, you are passing a pointer to an int. So how could it call the function which is expecting a reference to an int? The two are completely different types. And yes, adding const is permitted. If you had overloaded on constness though:

void A(const int*)
{
    cout << "const int*" << endl;
}

void A(int*)
{
    cout << "int*" << endl;
}

The non-const version would be selected as a better match.

With the template, things are different. Remember that pointers are types too. It is just as valid to deduce T as a pointer type. When you call B(b), the compiler can use this function:

template <typename T>
void B(const T*)
{
    cout << "const T*" << endl;
}

In which case T must be deduced as int, and const T* becomes const int*, a pointer to a const int.

Or the compiler can choose this function:

template <typename T>
void B(const T&)
{
    cout << "const T&" << endl;
}

In which case T is deduced as int*. And const T& then becomes int* const&, that is, a reference to a const pointer to int.

Since, in the second case, T maps exactly to what you actually passed in (a pointer to an int), it is the better match.

OTHER TIPS

No, the behavior is not different.

With B, T gets resolved to int* and the second overload's

int* const&

is a better match than the first overload's

int const*

Note that both are feasible, just the first one is better. So basically the template lets you get the most permissible access.

For A, there is really only one option, since the pointer is not convertible to a reference, and that is to drop the const.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top