条款5 相对显式类型声明,更倾向使用auto
基础知识
auto能大大方便变量的定义,可以表示仅由编译器知道的类型。
template<typename It> void dwim(It b, It e) { while(b != e) { //typename std::iterator_traits<It>::value_type currValue = *b; // old type auto currValue = *b; // new type } }
auto可以用来定义函数,如下:
auto derefURLess = [](const std::unique_ptr<Widget>& p1, const std::unique_ptr<Widget>& p2) { return *p1 < *p2; } // C++ 11 auto derefLess = [](const auto& p1, const auto& p2) { return *p1 < *p2; } // C++ 14
除了使用auto,还可以使用std::function类型来存储函数。其产生一个函数指针,但是可以指向任何可以像函数一样被调用的对象。形式如下:
std::function<bool(const std::unique_ptr<Widget>&, const std::unique_ptr<Widget>&)> derefURLess = [](const std::unique_ptr<Widget>& p1, const std::unique_ptr<Widget>& p2) { return *p1 < *p2; }
但是auto与std::function不同,auto仅仅存储闭包(closure),但是存储闭包的std::function模板的实例化,对于任何签名大小固定,当空间不够时会申请堆空间。结果是std::function相比auto使用更多的空间。
以下是一个不使用auto而会产生隐式转换而造成错误的例子:
std::unorder_map<std::string, int> m; for(const std::pair<std::string, int>& p : m) { ... } // 此处应为std::pair<const std::string, int>,所以会创建零时对象来绑定p
使用auto也会因为表达式的特殊而产生未曾预料的结果。
总结
- auto的变量必须被初始化,并且对因类型不符而引起的移植或效率问题免疫,并且可以简化重构过程,还可以减少输入
- auto变量会遇到条款2和6提到的陷阱