auto : 类型推导. 在使用c++的时候会常用, 就像在考虑STL时迭代器类型, 写模板的时候使用auto能少写代码, 也能帮助咱们避免一些隐患的细节.c++
auto
型别推导要求必须在定义时初始化, 毕竟须要根据对象的类型推导左值对象的型别.auto j; // error. 必须初始化 auto i = 0; // i 推导型别为 int vector<int> v; auto vv = v.cbegin(); // vv 推导型别为 const int*
auto
型别推导会忽略引用和顶层const, 因此要对对象加上想要的修饰.const int ci = 0; auto i = ci; // i 推导型别为 int, 忽略了顶层const int &ri = i; auto ii = ri; //ii 推导型别为 int, 忽略了引用
()
和=
对变量初始化, C++11增长了对定义的对象初始化的方法,可使用{}
对变量初始化c11以前的初始化方法编程
int i(0); // i 初始化 0 int j = 0; // j 初始化 0
c11后的初始化方法数组
auto i(0); auto j = i; // 支持c11前 auto ii{0}; // 使用 {} 进行初始化, 可是auto推导只能接受一个参数 auto jj = { 0 }; // jj 的推导型别为 initializer_list<int>型别
上面jj的推导竟然不是int型别, 而是 initializer_list<int>
, 这不能怪auto推导出问题, 这主要是后者的对象初始化就是使用={}
, 能够说是auto推导的是最精确的型别. 无论新添的初始化方法, 找一个习惯的就好了.函数
auto
最多见的就是与for
联用, 特别是类型特别复杂的时候. 可是auto又有多种选择, 如 : auto, auto &等, 不一样的选择其效率也不同.oop
auto
, 即 for(auto i:range) . 这使range中的每个元素都会产生一个副本, 因此即便修改了 i 也不会实际影响到range.const auto
, 及for(const auto i : range). 这也会是range的每个元素产生一个副本, 可是这个副本竟不能被修改.auto &
, 即for(auto &i : range). 引用, 由于i 直接引用range里面的元素, 因此并不会产生一个副本, 可是 i 的修改也会影响range里元素的值. 一般咱们须要修改range是会考虑用到.const auto&
, 即for(const auto &&i : range). i 直接引用range里面的元素, 因此并不会产生一个副本, 而且i 也不能修改. 通常初始化的是一个左值时并且是读取range里的元素时都是用const auto&
而不用auto
, 由于前者不会产生副本, 效率要高. 固然通常初始化的是一个左值时效率低, 可是若是是右值仍是使用const auto
效率高, 由于const auto &
须要把 i 存储在内存中的一个位置,间接访问会更消耗时间auto&&
, 即for(auto &&i : range). 若是初始化是左值, 那么 i 就是左值引用, 若是初始化是右值, 那么 i 就是右值引用,还有const auto &
, 固然具体的选择仍是看具体的状况而定.code
最后, 当用auto
推导多维数组的时, 保证除最内层循环外, 其余的外层循环都应该是引用类型, 不然很容易出错, 即 :对象
int a[10][10][10]; for (const auto &i : a) for(const auto &j : i) for(const auto k : j) ;
auto
初始化在平台上还有一点好处, 好比 :vector<int> v; unsigned size = v.size(); // size()返回size_t型别 auto sizet = v.size();
在32的平台unsigned
表明的是32位, size_t
是32位, 在64的平台unsigned
表明的也是23位, 可是size_t
倒是64位, 这样平台差别可能就会带来问题, 使用auto
代替就没有这样的问题.内存
不过只有这几点可能不会让人心动, 下面咱们还有auto的好处.ci
还记得在前言中个说过调用STL最好使用auto
推导型别, 若是你还记得map
与pair
吗? 是这样 map<pair<key, type>>
? 仍是map<pair<const key, type>>
? 答案是最后一种, 那么如今咱们就来分析的使用auto
推导仍是显示型别比较好.get
int main() { std::map<string, std::function<type(type, type)>>func = { { "+", [](auto i, auto j)->auto {return i + j; } }, { "-", [](auto i, auto j)->auto {return i - j; } }, { "*", [](auto i, auto j)->auto {return i * j; } }, { "/", [](auto i, auto j)->auto {return i / j; } } }; for (const auto &i : func) ; for(const std::pair<string, std::function<type(type, type)>> &pa : func) ; system("pause"); exit(EXIT_SUCCESS); }
看到上面的例子毫无问题, 可是深究起来显示型别仍是些不完美. 咱们知道map的key
不能被改变, 因此显示型别的string
与map的const string
不是匹配, 编译器就会将map对象都会产生一个临时对象再隐式的转为string
, 等等. 是否是注意到有一点了, 为了型别匹配赋值会产生临时变量, 那岂不是每一循环都会产生一个临时变量, 可是auto
型别推导就是精确匹配的, 不会产生临时变量.
可能以为将显示型别的key改成const string
就能解决这个问题了, 确实是这样, 可是若是没有注意到这一点细节, 那就会损失效率了, 使用auto能够彻底不想这些问题啊.
固然使用显示型别仍是型推导看实际也看我的, 不是必要.
auto
不能被声明为返回值,auto
不能做为形参,auto
不能被修饰为模板参数. 那么这里auto
还能怎么和函数关联起来? 能.
auto放在函数名前面告诉编译器,真正的返回值在函数声明以后. 简单说auto能够做为返回值占位符来使返回值后置.
就像这样来写.
auto Return(std::size_t N) -> std::size_t { return N; }
既然c++规定能够这样写确定有其意义. 其实这个写法主要用于template
中, 当返回值的类型是一个模板类型时使用, 而返回值类型经过decltype
来推导.
这里就解释一下decltype
的简单运用. , decltype
也是相似与auto
的关键字, 都可以进行参数类型推导, 可是decltype
必需要接受一个参数, 以下:
int i = 1; decltype(i) j = 1;
auto
与模板函数连用时用模板参数做为返回值. 由于编译器并不能直接推断出返回值为类型参数的实际类型, 因此在STL中采用traits
编程解决这个问题, 这里时另外一种实现方法.
首先看一个错误的例子:
template<class T1, class T2, class T3> T3 fun(T1 t1, T2 t2) {...}
T3的类型要在函数返回的时候才能知道, 而函数这样写就必需要编译期间就要知道返回值类型. 因此编译器会报错.
如下这样写就是正确的, 可是必须保证编译器能推导出类型.
template<class T1, class T2, class T3> T1 fun(T1 t1, T3 t3) {...}
使用auto将返回值类型放在最后, 就是告诉编译器真正的返回值在编译后动态获取, 而auto在这里的做用也称为返回值占位
template<class T1, class T2> auto fun(T1 t1, T2, t2) -> decltype(*t1) {...}
以上能够将返回类型放在函数尾作尾置是C11中的要求, 可是C14已经能够将返回型别放推导在函数头. 如 :
template<class T1> decltype(auto)fun() {...} // 这样的写法同上式同样
虽然规定可以这样写, 有时为了兼容也仍是写成尾置.
咱们可使用auto
来推断出new
对象的类型, 可是局限在于, 必须对new
出来的对象进行单一的初始化.
auto i = new int; // 这中写法根本没有用到auto的推导哦, 由于new的类型已经肯定了 auto i = new auto(1); // 这里就是用到了auto推导 auto size = new auto; // error, 不能推导出size的类型 auto j = new auto(1,2); // error, 只能接收一个初始化值
在const
中咱们分析到顶层const
会被忽略, 因此auto
是没法推断出顶层const, 即 :
auto i = new const auto(1); // 这里auto并无推导出顶层const, 因此i的类型其实是int const auto j = new const auto(1); // 只有显示的定义j的类型是const
若是想直接推导出顶层const的话, 最好仍是decltype
进行推导.
注意 : auto
推导只能推导出int, double等, 不能推导出short类型.
本节对C11的auto用法作了一个浅显的分析, 分别对使用auto
的好处, 定义时注意{}
对象也必须初始化, auto
在与for连用的时候要根据实际参数肯定选择哪一种实现, 这样效率才会达到最大, 固然通常都使用const auto&
和auto&&
. 最后还对auto
与函数返回值关联, 能够将返回型别放在函数名尾也能够, 这样的作法通常在模板中将模板参数做为返回值才考虑用, 平时也没必要这样定义函数.
参考 :
<< Effective Modern C++ >>