总的来说,使用auto可以帮助你实现正确、高效的变量声明,让代码更健壮,可维护性更高。
1.auto更安全
由于auto声明的变量,其类型推导自初始化物,所以他们必须被初始化。
int x; //可以未初始化
auto x; //error, 必须被初始化
auto x = 1; //ok, x -> int
这样就避免了你使用一个未初始化变量而不小心引出的bug。
2.auto更精确
有时候当你显示的声明一个变量的类型的时候,可能你写出的类型并不是正确的类型。考虑下面的例子:
int i = sizeof(arr); //sizeof的返回值是unsigned int
std::map<std::string, int> myMap;
...
...
for (const std::pair<std::string, int>& p : myMap)
{
//...
}
上面的代码初看起来没有问题,可是你忘了std::map的键是const,所以存放在map里的是std::pair<const std::string, int>,而不是我们写的那个。所以当你做循环时,每次都会生成一个临时对象,这个临时对象的类型就是你的p要绑定的类型。所以,不知不觉中你让你的代码更慢了。
3.当你不知道一个表达式的准确类型时
C++11以来,由于多了lambda表达式,你可能经常在算法中使用lambda,但是一个lambda表达式的类型该是什么呢?可能只有编译器才会知道。所以你可以这么写:
auto f = [] (int i) {std::cout << i << std::endl;}
还有我们经常在代码中写下这样的语句:
std::vector<int> v{1,2,3,4,5};
std::vector<int>::const_iterator ite = v.cbegin();
for (; ite != v.cend(); ++ite)
{
//....
}
是不是每次写出这种长长的类型都要敲击好多次键盘,为了我们的键盘寿命更长一点,我们就这么写吧:
for (auto ite = v.cbegin(); ite != v.cend(); ++ite)
{
//...
}
4.auto在模板中的应用
假如我们写一个函数,这个函数返回两个实参相加的结果,为了让其更加通用,我们会这样写:
template<typename T1, typename T2>
??? add(T1 t1, T2 t2)
{
return (t1+t2);
}
这个例子中,假如T1和T2的类型不一样,我们该怎么声明add的返回值类型呢?可以用decltype吗,假如我们这么写:
template<typename T1, typename T2>
decltype(t1+t2) add(T1 t1, T2 t2)
{
return (t1+t2);
}
但是,编译器没那么聪明,编译器是从前往后编译的,所以decltype用到的t1和t2,并没有被事前声明。但是你可以这么写:
template<typename T1, typename T2>
auto add(T1 t1, T2 t2) ->decltype(t1+t2)
{
return (t1+t2);
}
在C++14中,你可以简单的这么写:
template<typename T1, typename T2>
decltype(auto) add(T1 t1, T2 t2)
{
return (t1+t2);
}
在 c++17中,你连decltype也可以省掉,直接auto就可以了。
更多
当然有时候你会说每个变量都声明为auto,会降低代码的可读性。当然,是这样的。虽然你可以依赖IDE,鼠标悬停在变量上来查看变量的准确类型。使用auto不代表你在任何时候都要使用auto,而是尽可能的。