一、auto 的规则
- auto 不能出现二义性
const auto a = 1, b = 1.0;//编译报b错误
- auto 只相当于一个类型声明的"占位符"
const auto a = 1, b; //编译器报错,必须给b赋值,让编译推导出类型
二、auto 的推导规则
1.auto 不声明为指针,也可以推导出指针类型
int x = 0;
auto *b = &x; //auto 被推导为int
auto & c = x; // auto 被推导为int *
- 当表达式是一个引用类型的时候,auto 会把引用类型抛弃,直接推导成原始类型
auto &a = x;
auto b = a; //b 为int 类型
- 当表达式中带有const 或者volatile属性时,auto 会把const 属性抛弃掉,推导成non-const 类型
const int a = 1;
auto b = a;//b 类型为int
- 当const 和引用符号&结合时,会保留const
const int &a = x;
auto &b = a;//b 为const int &类型
通过上述,可以总结出两条规则:
1)当不声明为指针或引用时,auto 的推导结果和初始化表达式抛弃引用和cv(const 或 volatile)限定符后的类型一致
2) 当声明为指针或引用时,auto 的推导结果将保持初始化表达式的cv属性
二. auto 的限制
- auto 不能用于函数参数声明
void func(auto a = 1){} //编译器报错
- auto 无法定义数组
int arr[10] = {0};
auto rr[10] = arr; //auto 无法定义数组
- auto 无法推导出函数目标的参数
Bar<int> bar;
Bar<auto> bb = bar; //error,
- 用于成员变量时,auto 仅支持static const 的整型或者枚举型
class A
{
public:
A();
~A();
private:
static const auto a = 1;//只有这种auto 才是对的,其他的方式在成员变量中都是错的
};
三、什么时候和正确的使用auto
- 使用stl容易遍历的时候,可以使用auto 来简化
喜欢使用stl容易的同学,肯定对迭代器长长的类型很痛恨,代码写出来也不够简洁,如下对比
std::map<int, int> mapData;
mapData.insert(1, 1);
std::map<int, int>::iterator iter = mapData.begin(); //c98
auto iter11 = mapData.begin();//c++11,比c98简洁许多,效果确实一样
- 利用auto自动得出正确类型
string str = "ttt";
unsigned n = str.find("ABC");
if (n == string::npos)
{
std::cout << "not find";
}
else {
std::cout << "find";
}
上述代码,在32位程序中不会出现问题,但是64位系统中呢,为什么会出现结果为:find。这是因为string::npos的类型为size_type,它在32位系统表示长度与unsigned一样,但是在64位系统中则比unsigned能表示的最大值要大,于是出现了bug。
这个时候使用: auto n = str.find("ABC")则不会出现这个问题,他会正确推导出返回值的类型
- 正确使用auto
auto n = 1024 * 1024 * 1024 * 5;
char* buf = new char[n];
上述代码不会报错,但是将auto改成const int,在有些严格的编译器下就会报错,不能分配这么大内存,内存不足
- auto 不是万能的
有些普通类型会出错的问题,auto 也会出错,如:
std::vector<int> bigVector;
for (unsigned i = 0; i < bigVector.size(); ++i)
{ ... }
如果bigVector非常大,超过unsigned能表示的最大范围,此循环会变为无限循环,这时将unsigned改成auto 也不能完全避免
对于简单类型,auto的行为非常糟糕。是的,在最简单的情况下(自动x = y)它可以工作,但是一旦有其他构造,其行为就变得更加不可预测。更糟糕的是,错误将更难以发现,因为乍一看变量的类型并不那么明显。作为简单的凡人,这种情况,最好明确地指定类型。
四、decltype关键字的规则
decltype 用来推导表达式类型
- 语法格式
decltype(exp) //exp表示一个表达式 - 推导规则
1)exp是标识符、类访问表达式,decltype(exp) 和exp的类型一致
2)exp是函数调用,decltype(exp) 和返回值的类型一致
3)若exp是左值,则decltype(exp) 是exp类型的左值引用,否则和exp类型一致
- 对于纯右值,只有类类型可以携带cv限定符,普通类型一般会忽略cv限定符