一、C++ auto类型推导
1、引入auto关键字的背景
在 C++11 之前的版本(C++98 和 C++ 03)中,定义变量或者声明变量之前都必须指明它的类型,比如 int、char 等;但是在一些比较灵活的语言中,比如 C#、JavaScript、PHP、Python 等,程序员在定义变量时可以不指明具体的类型,而是让编译器(或者解释器)自己去推导,这就让代码的编写更加方便。C++11 为了顺应这种趋势也开始支持自动类型推导了!C++11 使用 auto 关键字来支持自动类型推导。
2、auto类型推导的语法与规则
C++11 赋予 auto 关键字新的含义,使用它来做自动类型推导。也就是说,使用了 auto 关键字以后,编译器会在编译期间自动推导出变量的类型,这样就不用手动指明变量的数据类型了。
注意:auto 仅仅是一个占位符,在编译器期间它会被真正的类型所替代。或者说,C++ 中的变量必须是有明确类型的,只是这个类型是由编译器自己推导出来的。使用 auto 类型推导的变量必须马上初始化,这个很容易理解,因为 auto 在 C++11 中只是“占位符”,并非如 int 一样的真正的类型声明。下面的做法在编译时会报错
int main()
{
auto n;
auto p = &n;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2.1、对于普通类型的推导
对于普通类型推断(没有 const 也不掺杂引用的),直接根据表达式右边值的类型进行推断
auto n = 10;
auto f = 12.8;
auto p = &n;
auto url = "http://c.biancheng.net/cplus/";
- 1
- 2
- 3
- 4
第 1 行中,10 是一个整数,默认是 int 类型,所以推导出变量 n 的类型是 int。
第 2 行中,12.8 是一个小数,默认是 double 类型,所以推导出变量 f 的类型是 double。
第 3 行中,&n 的结果是一个 int* 类型的指针,所以推导出变量 p 的类型是 int*。
第 4 行中,由双引号""包围起来的字符串是 const char* 类型,所以推导出变量 url 的类型是 const char*,也即一个常量指针。
2.2、使用引用进行推导
使用引用进行推断,实际上就是使用引用对象的类型进行推断,此时引用特性会被丢弃,如果定义的对象需要成为引用,就自己在 auto 后面加上 & 来定义对象
int x = 0;
auto *p1 = &x; //p1 为 int *,auto 推导为 int
auto p2 = &x; //p2 为 int*,auto 推导为 int*
auto &r1 = x; //r1 为 int&,auto 推导为 int
auto r2 = r1; //r2 为 int,auto 推导为 int
- 1
- 2
- 3
- 4
- 5
2.3、auto与const进行结合
使用带有 const 属性的对象进行推断时,如果定义的对象不是指针或者引用,则 const 属性会被丢弃,否则 const 属性会保留
const int c = 10;
auto a1 = c; // auto 此时是 int,const 属性被丢弃
auto &a2 = c; // auto 此时是 const int,const 属性保留
- 1
- 2
- 3
- 4
3、auto的限制
- 使用 auto 的时候必须对变量进行初始化
- auto 不能在函数的参数中使用,在定义函数的时候只是对参数进行了声明,指明了参数的类型,但并没有给它赋值,只有在实际调用函数的时候才会给参数赋值;而 auto 要求必须对变量进行初始化,所以这是矛盾的
- auto 关键字不能定义数组
4、auto的应用
4.1、使用auto定义迭代器
auto 的一个典型应用场景是用来定义 stl 的迭代器
#include <vector>
using namespace std;
int main(){
vector< vector<int> > v;
auto i = v.begin(); //使用 auto 代替具体的类型
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
4.2、泛型编程
auto 的另一个应用就是当我们不知道变量是什么类型,或者不希望指明具体类型的时候,比如泛型编程中
#include <iostream>
using namespace std;
class A{
public:
static int get(void){
return 100;
}
};
class B{
public:
static const char* get(void){
return "http://c.biancheng.net/cplus/";
}
};
template <typename T>
void func(void){
auto val = T::get();
cout << val << endl;
}
int main(void){
func<A>();
func<B>();
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24