C++ auto关键字
300 Words | Read in about 2 Min | View times
Overview
auto
关键字在C++11中进行了重新定义,抛弃了传统C++中auto
是用来自动延长对象生命周期的用法,而是将其用作类型自动推导。本节内容主要讨论auto
的用法以及一些注意事项。
本系列文章将包括以下领域:
本章其他内容请见 《现代C++》
auto关键字的用法
用auto
关键字来声明变量类型的时候,会根据变量的初始化数值类型自动推导出变量的匹配类型,与decltype
关键字的作用类似。
auto
的类型推导发生在编译期,而不是运行期,所以使用auto
关键字声明变量类型并不会降低效率。
代替冗长的类型声明
特别是对于容器迭代器的类型声明非常有用:
1std::map<int, int> mp;
2//传统写法,非常冗长
3std::map<int, int>::iterator itr = mp.find(1);
4if (itr != mp.end()) {
5 //...
6}
7
8//C++11写法
9auto itr2 = mp.find(2);
10if (itr2 != mp.end()) {
11 //...
12}
用于声明模板函数中依赖模板参数的变量类型
1template<typename T1, typename T2>
2void Plus(T1 x, T2 y) {
3 auto result = x + y;
4 //...
5}
T1
和T2
的类型需要在具体调用的时候才能进行模板初始化,在此之前无法得知其真实类型,如果此时不用auto
来声明result
的类型,函数就无法定义。
用于声明模板函数返回值类型
1template<typename T1, typename T2>
2auto Multiply(T1 x, T2 y) -> decltype(x * y) {
3 return x * y;
4}
当模板函数的返回值类型依赖于模板参数,也需要使用auto
来声明返回值类型。此处的auto
也称为返回值占位符,只是代表一个返回值类型的占位,真正的类型是后面的decltype
语句。
这里不使用decltype(x * y) Multiply(T1 x, T2 y)
,是因为如果前置decltype
语句,此时的x
和y
还未声明,不能直接使用。
auto关键字的注意事项
auto变量定义时必须初始化
1auto a1 = 10; //ok
2auto a2; //error
auto关键字修饰
auto
关键字可以结合const
、volatile
、*
、&
、&&
一起使用。
auto定义变量序列时必须始终推导为同一类型
1auto a1 = 10, b1 = 20, c1 = 30; //ok
2auto a2 = 10, b2 = 20.0, c2 = 'a'; //error
如果初始化表达式是引用
auto
推导去除引用语义
1int a = 10;
2int& b = a;
3
4auto c = b; //c的类型推导为int,而非int&
auto&
推导保留引用语义
1int a = 10;
2int& b = a;
3
4auto& d = b; //d的类型才是int&
如果初始化表达式带有const和volatile语义
auto
推导去除const
和volatile
语义,除非显示声明
1const int a = 10;
2auto b = a; //b的类型推导为int,而非const int
3const auto c = a; //c的类型才是const int
auto&
保留const
和volatile
语义
1const int a = 10;
2auto& b = a; //b的类型推导为const int&
这是因为如果auto
推导的类型去除了const
,那么b
就变成了非const
引用,可以修改a
的值,这显然是错误的。
如果初始化表达式是数组
auto
推导成指针类型
1int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
2auto brr = arr;
3std::cout << typeid(arr).name() << ", " << typeid(brr).name() << std::endl; //A10_i,Pi
其中A10_i
表示int[10]
,而Pi
表示int*
。
auto&
推导为数组类型
1int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
2auto& brr = arr;
3std::cout << typeid(brr).name() << std::endl; //A10_i, A10_i
函数或模板参数不能声明为auto
1void func(auto param) { //error
2 //...
3}
auto仅是占位符,不是一个真正的类型
由于auto
仅仅是代表占位,不是真正的类型,故不能对auto
使用以类型为操作数的操作符,如sizeof()
和typeid()
。