模板类型推导
理解函数模板类型推导:
一段函数模板的伪码大概是这样的:
template<typename T>
void f(ParamType param);
调用这个函数会是这样:
f(expr); // 用一些表达式来调用f
在编译的时候,编译器通过expr来进行推导出两个类型:一个是T的,另一个是ParamType。通常来说这些类型是不同的,因为 ParamType通常包含一些类型的装饰,比 如const或引用特性。注意T的类型不仅和expr的类型独立,而且和Param的形式独立。
下面是三个例子:
1.Param是一个指针(包括指向const的指针)或者一个引用(包括const引用)(但并不是一个通用引用或则说万能引用)
2.Param是一个通用引用
附universal reference:如果一个函数的template parameter有着T&&的格式,且有一个deduce type T.或者一个对 象被生命为auto&&,那么这个parameter或者object就是一个universal reference.
3.Param既不是指针,也不是引用
在第一种情况和第二种情况下,T和param类型推到中,调用函数的实参的const特性将给予保留。
1.第一种情况:
当Param是一个指针或者非通用的引用:在这种情况下类型推导的过程如下
-1. 如果 expr 的类型是个引用,忽略引用的部分。
-2. 然后利用 expr 的类型和 ParamType 对比去判断 T 的类型。
# include <iostream>
template <typename T>
void f(T& param)
{
//param = 270; //作为测试,这里假设param的数据类型支持赋值
std::cout << param << std::endl;
}
int main()
{
int x = 27; //x是一个int
const int y = x; //y是一个const int
const int& z = y; //z是一个const int的引用
//f(x); //T是int,Param是int &
//f(y); //T是const int,Param是const int &
f(z); //T是const int,Param是const int &
return 0;
}
2.第二种情况:
当Param是一个通用引用:如果expr是一个左值,那么T和Param都将被推导为左值引用。如果是右值,那么就遵循普通法则
# include <iostream>
template <typename T>
void f(T&& param)
{
std::cout << param << std::endl;
}
int main()
{
int x = 27; //x是一个int
const int y = x; //y是一个const int
const int& z = y; //z是一个const int的引用
f(x); //T是一个int &,param是一个int &
f(y); //T是一个const int &,param是一个const int &
f(z); //T是一个const int &,param是一个const int &
f(100); //T是一个int,Param是一个int &&
return 0;
}
3.第三种情况:
当Param既不是指针也不是一个引用:在这种情况下由于param既不是一个指针也不是一个引用,调用函数传递给形参param的是一个实参的副本。因此调用函数的实参的const特性将不被保留。其推导法则为:
-1.和之前一样,如果expr的类型是个引用,将会忽略引用的部分。
-2.如果在忽略 expr 的引用特性,expr是个const的,也要忽略掉 const。如果 是volatile,照样也要忽略掉(volatile对象并不常见)。
# include <iostream>
template <typename T>
void f(T param)
{
param = 270;
std::cout << param << std::endl;
}
int main()
{
int x = 27; //x是一个int
const int y = x; //y是一个const int
const int& z = y; //z是一个const int的引用
f(x); //T是一个int,Param是一个int
f(y); //T是一个int,Param是一个int
f(z); //T是一个int,Param是一个int
return 0;
}
理解auto模板类型推导
除了一个例外,auto模板类型推导就是函数模板类型推导。当一个变量被声明为auto,auto相当于模板中的T,而对变量做的相关的类型限定就像ParamType。这个例外是当使用c++11的语法使用花括号来初始化auto变量时:
auto a = {100};//此时a的类型被推导为std::intializer_list<int>