C++模板类型推导

模板类型推导

对于模板函数来说,编译器需要根据实际传入的参数来推导模板类型T。例如,假设我们有下面这个模板函数:

tempalte
void f(T& param); // param si a reference

同时声明了这些变量:

int x = 27;				// x is an int
const int cx = x;		// cx is a const int
const int& rx = x;		// rx is a reference to x as a const int

那么调用模板函数时,编译器推导出的模板类型分别为:

f(x)		// T is int, param's type is int&
f(cx)		// T is const int, param's type is const int&
f(rx)		// T is const int, param's type is const int&

可以发现,同样是整型变量,带不带const、是不是reference,类型推导的结果是不一样的。回到刚开始声明的模板函数,我们声明了参数类型为T&,如果声明为T,或者是T&&,又会得到怎样的结果?我们用表格来总结一下:

x cx rx rvalue
void f(T& param) T int const int const int x
param int& const int& const int& x
void f(const T& param) T int int int int
param const int& const int& const int& const int&
void f(T&& param) T int& const int& const int& int
param int& const int& const int& int&&
void f(T param) T int int int int
param int int int int
猛一看表格,会让人眼花缭乱。死记硬背是记不住的,我们找一找其中的规律。
  • 一般情况下,param的类型是最完整的类型,继承了形参中声明的cr(const和reference)和实参总带过来的cr。但有两个特例:
    • 特例一:当形参时通用引用(T&&作为模板参数时称为通用引用)时,param根据具体的实参类型,推导为左值引用或者右值引用;
    • 特例二:当形参不是引用时,实参到形参为值传递,去除所有cr修饰符。
  • T中是否包含cr修饰符,取决于param的修饰符是否已在形参中声明过。也就是说,T中修饰符不会与形参中已声明的修饰符重复。

为什么我们需要知道这些规则呢?这是因为,有时候需要根据传入的param的类型构造与之相关联的其它类型的对象。比如我们想要在函数内部构造一个与param同类型但去除cr修饰符的对象,那么就应该把形参声明为const T& param,然后声明T obj这个对象。这是因为上表中第4行表明了,无论实参包含了什么修饰符,无论是左值还是右值,T都是不带任何修饰符的单纯类型。当然,声明为T param也是可以的,但这种情况下参数就是值传递了。所以说,根据实际情况选择合适的模板参数类型是很重要的。

最后,为了更容易实践,我们总结出下面三个推荐用法:

  • 想要按值传递,将模板函数参数声明为T param
  • 想要按引用传递,但不考虑右值时,将模板函数参数声明为const T& param
  • 想要按引用传递,但要区分左值和右值时,将模板函数声明为T&& param

你可能感兴趣的:(C++,模板类型推导,C++11,模板类型推导)