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