关于下面的代码,编译器如何选择调用哪个模板函数?如果省略const T&function,则始终调用T&函数.如果省略T&函数,则始终调用const T&函数.如果两者都包括在内,结果如下.
#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
*/
Run Code Online (Sandbox Code Playgroud)
以下是编译器所经历的过程的简要总结。它并没有涵盖所有内容,但它可以帮助您入门。
在这种情况下,做出的决定与非模板化函数相同。给定void f(int&)和void f(const int&),第一个将被选择为常规整数,第二个将被选择为常量整数。通过这种方式,参数可以更好地匹配输入:如果您提供可以修改的变量,它会调用可以修改它们的函数,如果您提供无法修改的变量,它会调用无法修改它们的函数。
在示例代码中,pi2被声明为 a const int *,是指向常量数据的非常量指针。因此,在您的函数中,您可以更改t,但不能更改*t。相比之下,pi3是指向非常量数据的常量指针。所以你可以改变*t但不能t。
如果您稍微更改了代码:
function(*pi1);
function(*p12);
function(*pi3);
function(*pi4);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,第一个和第三个都将解析为T&版本,因为*pi1和*pi3都是类型int&,因此可以修改。 *pi2和*pi4都是const int&,因此它们解决了const T&过载问题。