Regarding the below code, how does the compiler choose which template function to call?
If the const T& function is omitted, the T& function is always called.
If the T& function is omitted, the const T& function is always called.
If both are included, the results are as below.
#include <iostream>
#include <typeinfo>
template <typename T>
void function(const T &t)
{
std::cout << "function<" << typeid(T).name() << ">(const T&) called with t = " << t << std::endl;
}
template <typename T>
void function(T &t)
{
std::cout << "function<" << typeid(T).name() << ">(T&) called with t = " << t << std::endl;
}
int main()
{
int i1 = 57;
const int i2 = -6;
int *pi1 = &i1;
int *const pi3 = &i1;
const int *pi2 = &i2;
const int *const pi4 = &i2;
function(pi1); ///just a normal pointer -> T&
function(pi2); ///cannot change what we point to -> T&
function(pi3); ///cannot change where we point -> const T&
function(pi4); ///cannot change everything -> const T&
return 0;
}
/* g++ output:
function<Pi>(T&) called with t = 0x22cd24
function<PKi>(T&) called with t = 0x22cd20
function<Pi>(const T&) called with t = 0x22cd24
function<PKi>(const T&) called with t = 0x22cd20
*/
/* bcc32 output:
function<int *>(T&) called with t = 0012FF50
function<const int *>(T&) called with t = 0012FF4C
function<int *>(const T&) called with t = 0012FF50
function<const int *>(const T&) called with t = 0012FF4C
*/
/* cl output:
function<int *>(T&) called with t = 0012FF34
function<int const *>(T&) called with t = 0012FF28
function<int *>(const T&) called with t = 0012FF34
function<int const *>(const T&) called with t = 0012FF28
*/
Here is a brief summary of the process the compiler goes through. It doesn’t cover everything, but it gets you started.
In this case, the decision is made the same as a non-templated function. Given
void f(int&)andvoid f(const int&), the first will be chosen for regular ints, and the second for const ints. The parameters simply match the inputs better this way: if you provide a variable you can modify, it calls a function that can modify them, if you provide a variable you can not modify, it calls a function that can not modify them.In your sample code,
pi2, being declared as aconst int *, is a non-constant pointer to constant data. So within your function, you can changet, but not*t. By contrast,pi3is a constant pointer to non-constant data. So you can change*tbut nott.If you changed your code slightly:
In this case, the first and third would both resolve to the
T&version, because*pi1and*pi3are both of typeint&and can therefore be modified.*pi2and*pi4are bothconst int&, so they resolve to theconst T&overload.