现代C++(C++98之后)(暂时主要了解C++11)除去模板的类型推导,增加了两个新特性
auto和decltype,本文将对类型推导做个全方位的剖析,做不到全方位的话,那我也无能为力哈哈哈(接着看书)
以下来自
template<typename T>
void f(ParamType param);
//调用
f(expr);
第一个问题,编辑器怎么推导的,让我们来考虑以下情况
std::string str;
int n = str;
这里编辑器会报错,因为string不能隐式转换成int,也就是说,编辑器有能力知道等号右边的类型是什么,从而去推导左边的类型,类型推导大致就是这个原理。
因此
在编译的时候,编辑器会expr 来进行推导出两个类型
这两个在大多数情况下是不相同的,因为ParamType会加上一个限定装饰,类似const或者引用,举个栗子
template<typename T>
void f(const T& param); // ParamType是const T&
以下会用三个例子来分析类型推导
非通用,占个坑,看完再补
非通用(&&)就是不是通用的,而通用则是用涉及到右值引用和完美转发,简单讲,通用引用可以实现输出左值推导成左值,输入右值推导成右值
类型推导的流程:
举个栗子
模板
template<typename T>
void f(T& param); // param是一个引用类型
变量声明
int x = 27; // x是一个int
const int cx = x; // cx是一个const int
const int& rx = x; // rx是const int的引用
类型推导结果
f(x); // T是int,param的类型时int&
f(cx); // T是const int, param的类型是const int&
f(rx); // T是const int,param的类型时const int&
结论
通用的引用参数,就需要涉及到右值引用
函数模板使用一个类型参数 T ,一个通用的引用参数的申明类型是 T&&
条款
举个栗子
template<typename T>
void f(T&& param); // param现在是一个通用的引用
int x = 27; // 和之前一样
const int cx = x; // 和之前一样
const int& rx = x; // 和之前一样
f(x); // x是左值,所以T是int&,param的类型也是int&
f(cx); // cx是左值,所以T是const int&,param的类型也是const int&
f(rx); // rx是左值,所以T是const int& param的类型也是const int&
f(27); // 27是右值,则T是int,param的类型是int&&
当ParamType 既不是指针也不是引用,我们把它处理成pass-by-value(值传递)
准则
和之前一样,如果 expr 的类型是个引用,将会忽略引用的部分。
如果在忽略 expr 的引用特性之后,expr 是个 const的,也要忽略掉const。如果
是volatile ,照样也要忽略掉
这种就比较简单了
数组名通常会跟指针扯上关系(一个数组会被退化成一个指向其第一个元素的指针)
const char name[] = "J. P. Briggs"; //name的类型是const char[13]
const char * ptrToName = name; //数组被退化成指针
这时,如果对数组名进行推导的话
template<typename T>
void f(T param); // 模板拥有一个按值传递的参数
f(name); // T和param的类型会被推到成什么呢?
因为数组参数声明会被当做指针参数,传递给模板函数的按值传递的数组参数会被退化成指
针类型,意味着在模板f的调用中,模板参数T被推导成const char*
但是!如果声明是数组的引用的话,结果完全不一样!
template<typename T>
void f(T& param); // 引用参数的模板
f(name); // 传递数组给f
这时,类型推导出的就是数组!!!(什么鬼)同时,类型推导包括了数组的长度
函数参数tm也能被推导函数指针
除了一个例外, auto 类型推导就是模板类型推导
从前面我们了解到,在调用 f的地方,编译器使用expr来推导T和ParamType 的类型。
当一个变量被声明为auto ,auto 相当于模板中的T,而对变量做的相关的类型限定就像ParamType
这里的情况也有三种
通过传入的参数类型(左值还是右值),结合类型声明(引用类型,const类型等),判断出T的类型
auto类型推导通常和模板类型推导类似,但是auto 类型推导假定花括号初始化代表的
类型是 std::initializer_list ,但是模板类型推导却不是这样
auto在函数返回值或者lambda参数里面执行模板的类型推导,而不是通常意义
的auto 类型推导
给定一个变量名或者表达式, decltype会告诉你这个变量名或表达式的类型