C++11auto关键字详解
在C++11 之前的版本(C++98 和 C++ 03)中,定义变量或者声明变量之前都必须指明它的类型,⽐如 int、char 等;程序员在定义变量时可以不指明具体的类型,⽽是让编译器(或者解释器)⾃⼰去推导,这就让代码的编写更加⽅便。
C++11 为了顺应这种趋势也开始⽀持⾃动类型推导了!C++11 使⽤ auto 关键字来⽀持⾃动类型推导。
auto 类型推导的语法和规则
在之前的 C++ 版本中,auto 关键字⽤来指明变量的存储类型,它和 static 关键字是相对的。auto 表⽰变量是⾃动存储的,这也是编译器的默认规则,所以写不写都⼀样,⼀般我们也不写,这使得 auto 关键字的存在变得⾮常鸡肋。
C++11 赋予 auto 关键字新的含义,使⽤它来做⾃动类型推导。也就是说,使⽤了 auto 关键字以后,编译器会在编译期间⾃动推导出变量的类型,这样我们就不⽤⼿动指明变量的数据类型了。
auto 关键字基本的使⽤语法如下:
auto name = value;
name 是变量的名字,value 是变量的初始值。
注意:auto 仅仅是⼀个占位符,在编译器期间它会被真正的类型所替代。或者说,C++ 中的变量必须是有明确类型的,只是这个类型是由编译器⾃⼰推导出来的。
auto 类型推导的简单例⼦:
auto n = 10;
auto f = 12.8;
auto p = &n;
auto url = "c.biancheng/cplus/";
下⾯我们来解释⼀下:
第 1 ⾏中,10 是⼀个整数,默认是 int 类型,所以推导出变量 n 的类型是 int。
第 2 ⾏中,12.8 是⼀个⼩数,默认是 double 类型,所以推导出变量 f 的类型是 double。
第 3 ⾏中,&n 的结果是⼀个 int* 类型的指针,所以推导出变量 p 的类型是 int*。
第 4 ⾏中,由双引号""包围起来的字符串是 const char* 类型,所以推导出变量 url 的类型是 const char*,也即⼀个常量指针。
我们也可以连续定义多个变量:
int n = 20;
auto *p = &n, m = 99;五一节经典祝福语简短
先看前⾯的第⼀个⼦表达式,&n 的类型是 int*,编译器会根据 auto *p 推导出 auto 为 int。后⾯的 m 变量⾃然也为 int 类型,所以把
99 赋值给它也是正确的。
注意1:推导的时候不能有⼆义性。在本例中,编译器根据第⼀个⼦表达式已经推导出 auto 为 int 类型,那么后⾯的 m 也只能是 int 类型,如果写作m=12.5就是错误的,因为 12.5 是double 类型,这和 int 是冲突的。
注意2:使⽤ auto 类型推导的变量必须马上初始化,这个很容易理解,因为 auto 在 C++11 中只是“占位符”,并⾮如 int ⼀样的真正的类型声明。
auto 的⾼级⽤法
auto 除了可以独⽴使⽤,还可以和某些具体类型混合使⽤,这样 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个表达式中,p1为 int* 类型,也即 auto * 为 int *,所以 auto 被推导成了 int 类型。
第 2个表达式中,p2为 int* 类型,auto 被推导为 int* 类型。
第 3个表达式中,r1 为 int & 类型,auto 被推导为 int 类型。
第 4个表达式中,r1 本来是 int& 类型,但是 auto 却被推导为 int 类型,这表明当=右边的表达式是⼀个引⽤类型时,auto 会把引⽤抛弃,直接推导出它的原始类型。
接下来,我们再来看⼀下 auto 和 const 的结合:
int x = 0;
const auto n = x; //n 为 const int ,auto 被推导为 int
auto f = n; //f 为 const int,auto 被推导为 int(const 属性被抛弃)
新农村建设实践报告const auto &r1 = x; //r1 为 const int& 类型,auto 被推导为 int
auto &r2 = r1; //r1 为 const int& 类型,auto 被推导为 const int 类型
电脑住宅ppt
下⾯我们来解释⼀下:
第 1个表达式中,n 为 const int,auto 被推导为 int。
第 2个表达式中,n 为 const int 类型,但是 auto 却被推导为 int 类型,这说明当=右边的表达式带有 const 属性时, auto 不会使⽤ const 属性,⽽是直接推导出 non-const 类型。
第 3个表达式中,auto 被推导为 int 类型,这个很容易理解,不再赘述。
第 4个表达式中,r1 是 const int & 类型,auto 也被推导为 const int 类型,这说明当 const 和引⽤结合时,auto 的推导将保留表达式的 const 类型。
最后我们来简单总结⼀下 auto 与 const 结合的⽤法:
当类型不为引⽤时,auto 的推导结果将不保留表达式的 const 属性;
当类型为引⽤时,auto 的推导结果将保留表达式的 const 属性。
auto 的限制
前⾯介绍推导规则的时候我们说过,使⽤ auto 的时候必须对变量进⾏初始化,这是 auto 的限制之⼀。那么,除此以外,auto 还有哪些其它的限制呢?
1) auto 不能在函数的参数中使⽤。
这个应该很容易理解,我们在定义函数的时候只是对参数进⾏了声明,指明了参数的类型,但并没有给它赋值,只有在实际调⽤函数的时候才会给参数赋值;⽽ auto 要求必须对变量进⾏初始化,所以这是⽭盾的。
2) auto 不能作⽤于类的⾮静态成员变量(也就是没有 static 关键字修饰的成员变量)中。
3) auto 关键字不能定义数组,⽐如下⾯的例⼦就是错误的:
char url[] = "c.biancheng/";
auto str[] = url;  //arr 为数组,所以不能使⽤ auto
4) auto 不能作⽤于模板参数,请看下⾯的例⼦:
template <typename T>
class A{
//TODO:
};
int main(){
A<int> C1;
A<auto> C2 = C1; //错误
return 0;
}
auto 的应⽤
说了那么多 auto 的推导规则和⼀些注意事项,那么 auto 在实际开发中到底有什么应⽤呢?下⾯我们列举两个典型的应⽤场景。
津市牛肉粉
1.使⽤ auto 定义迭代器
auto 的⼀个典型应⽤场景是⽤来定义 stl 的迭代器。
我们在使⽤ stl 容器的时候,需要使⽤迭代器来遍历容器⾥⾯的元素;不同容器的迭代器有不同的类型,在定义迭代器时必须指明。⽽迭代器的类型有时候⽐较复杂,书写起来很⿇烦,请看下⾯的例⼦:
#include <vector>
using namespace std;
int main(){
vector< vector<int> > v;
vector< vector<int> >::iterator i = v.begin();
return 0;
}
可以看出来,定义迭代器 i 的时候,类型书写⽐较冗长,容易出错。然⽽有了 auto 类型推导,我们⼤可不必这样,只写⼀个 auto 即可。修改上⾯的代码,使之变得更加简洁:
#include <vector>
using namespace std;
int main(){
vector< vector<int> > v;
auto i = v.begin(); //使⽤ auto 代替具体的类型
return 0;
}
auto 可以根据表达式 v.begin() 的类型(begin() 函数的返回值类型)来推导出变量 i 的类型。
2.auto ⽤于泛型编程
auto 的另⼀个应⽤就是当我们不知道变量是什么类型,或者不希望指明具体类型的时候,⽐如泛型编程中。我们接着看例⼦:
public:金莎的老公是谁
static int get(void){
return 100;
}
};
class B{
public:
static const char* get(void){
return "c.biancheng/cplus/";
}
};
template <typename T>
void func(void){
auto val = T::get();
cout << val << endl;
}
int main(void){
func<A>();
func<B>();
return 0;
}
运⾏结果:
100
c.biancheng/cplus/
本例中的模板函数 func() 会调⽤所有类的静态函数 get(),并对它的返回值做统⼀处理,但是 get() 的返回值类型并不⼀样,⽽且不能⾃动转换。这种要求在以前的 C++ 版本中实现起来⾮常的⿇烦,需要额外增加⼀个模板参数,并在调⽤时⼿动给该模板参数赋值,⽤以指明变量 val 的类型。
但是有了 auto 类型⾃动推导,编译器就根据 get() 的返回值⾃⼰推导出 val 变量的类型,就不⽤再增
加⼀个模板参数了。
下⾯的代码演⽰了不使⽤ auto 的解决办法:
public:
static int get(void){
return 100;
}
};
class B{
public:
static const char* get(void){
return "c.biancheng/cplus/";
照片
}
};
template <typename T1, typename T2> //额外增加⼀个模板参数 T2 void func(void){
T2 val = T1::get();
cout << val << endl;
}
int main(void){
//调⽤时也要⼿动给模板参数赋值
func<A, int>();
func<B, const char*>();
return 0;
}