auto 关键词
auto 仅仅是一个占位符,在编译器期间它会被真正的类型所替代。
使用 auto 类型推导的变量必须马上初始化,这个很容易理解,因为 auto 在 C++11 中只是“占位符”,并非如 int 一样的真正的类型声明。
顶层 const 和底层 const
由于指针本身是一个对象,又可以指向一个对象,所以存在顶层(指针本身这个对象)和底层 const(指针指向的对象)
int i = 0; int *const p1 = &i; // 这里 const 是顶层 const const int ci = 42; // 这里 const 是顶层 const(用于表征某个对象是常量,不涉及指针) const int *p2 = &ci; // 这里 const 是底层 const(用于表征指针指向的对象是常量,涉及指针) const int *const p3 = p2; // 左边是底层 const,右边是顶层 const const int &r = ci; // 用于声明引用的 const 都是底层 const
当执行对象的拷贝时,常量是顶层 const 还是底层 const 有着明显的区别:
// 顶层 const 不影响对象的拷贝操作
i = ci; // 正确,ci 的顶层 const 不影响该对象拷贝操作 p2 = p3; // 正确,p3 的顶层 const 不影响该对象拷贝操作(p2,p3同时指向相同的对象类型)
// 在执行对象拷贝时,两边的底层 const 必须一致,或者两个对象的数据类型必须能够转换
int *p = p3 // 错误,p3 有底层 const 而 p 没有
p2 = p3 // 正确,p2, p3都有底层 const
p2 = &i // 正确,右边的 int* 能转换为 const int*
int &r = ci // 错误,const int 不能转换为 int
const int &r2 = i; // 正确,int 能转换为 const int(也可以理解为:const int& 能绑定在一个普通的 int 上)
auto 类型推导规则
1. 简单推导
auto n = 10; // auto 为 int auto f = 12.8; // auto 为 double auto p = &n; // auto 为 int* auto url = "http://c.biancheng.net/cplus/"; // auto 为 const char*, 即指向常量字符的指针
// 在本例中,编译器根据第一个子表达式已经推导出 auto 为 int 类型,那么后面的 m 也只能是 int 类型,如果写作 m = 12.5 就是错误的
int n = 20;
auto *p = &n, m = 99;
2.省略引用
引用实际是代表引用的对象,特别当引用作为初始值时,真正参与初始化的其实是引用对象的值。
int i = 0; int &r = i; auto a = r; // auto 为 int
3. 省略顶层 const
int i = 0; const int ci = i; const int &cr = ci; auto b = ci; // auto 为 int,忽略顶层 const auto c = cr; // auto 为 int,忽略顶层 const 和 引用 auto d = &i; // auto 为 int* auto e = &ci; // auto 为 const int*(即指向一个常量整数的指针)
4. 显式声明顶层 const
const auto f = ci; // ci 为 const int;auto 为 int;f 的类型为 const int
5. 显示声明引用(保留顶层 const)
设置一个类型为 auto 的引用时,初始值中的 顶层 const 得以保留。
auto &g = ci; // ci 为 const int;auto 为 const int;g 的类型为 const int&
auto &h = 42 // 错误,不能为非常量引用 绑定 字面值
const auto &j = 42; // 正确,可以为常量引用 绑定 字面值
6. 一个语句中定义多个变量
每个表达式中的初始值的类型要保持一致
// ci 为 const int 类型 auto &m = ci, *p = &ci; // m 的类型是 const int&(对常量整数的引用);p 的类型是 const int*(指向常量整数的指针)[ci 和 &ci 的类型当然一致]
auto &n = i, *p2 = &ci; // 错误,i 和 &ci 的类型不一致 (i 的类型是 int,而 &ci 的类型是 const int)
auto 的限制
1. 使用 auto 的时候必须对变量进行初始化;
2. auto 不能在函数的参数中使用。(违反第一条原则)
3. auto 不能作用于类的非静态成员变量(也就是没有 static 关键字修饰的成员变量)中。
4. auto 关键字不能定义数组,比如下面的例子就是错误的:
char url[] = "http://c.biancheng.net/";
auto str[] = url; //arr 为数组,所以不能使用 auto
5. auto 不能作用于模板参数,请看下面的例子:
template <typename T> class A{ //TODO: }; int main(){ A<int> C1; A<auto> C2 = C1; //错误 return 0; }
decltype 关键词
decltype 推导规则
decltype 的推导规则主要有以下3条:- 如果 exp 是一个不被括号
( )
包围的表达式,或者是一个类成员访问表达式,或者是一个单独的变量,那么 decltype(exp) 的类型就和 exp 一致,这是最普遍最常见的情况。 - 如果 exp 是函数调用,那么 decltype(exp) 的类型就和函数返回值的类型一致。
- 如果 exp 是一个左值,或者被括号
( )
包围,那么 decltype(exp) 的类型就是 exp 的引用;假设 exp 的类型为 T,那么 decltype(exp) 的类型就是 T&。