条款6 当推断意外类型时使用显式的类型初始化语句
基础知识
当使用std::vector<bool>的时候,类型推断会出现问题:
std::vector<bool> features(const Widget& w);
// OK
bool highPriority = features(w)[];
processWidget(w, highPriority);
// ERROR
auto highPriority = features(w)[];
processWidget(w, highPriority); // undefined behavior
std::vector<bool>的operator[]操作并不返回一个bool类型,而是返回一个std::vector<bool>::reference(一个std::vector<bool>的内嵌类)。
存在以上类型是因为std::vector<bool>返回紧凑形式的bool,每一位表示一个bool。vector的operator[]操作返回T&,但是C++静止引用为bit的形式。所以std::vector<bool>的operator[]操作返回一个类似bool&的对象std::vector<bool>::reference,并且隐式转换为bool。
在使用auto时候,返回可能为一个指针以及偏移量,但随后指向出的内存会被释放,所以highPriority会变成一个悬垂指针(dangling pointer)。
一些代理类十分明显,如std::shared_ptr和std::unique_ptr,有一些不明显如std::vector<bool>和std::bitset。
C++中的有些库使用了一种叫做表达式模板(expression template)的技术来提高算术运算的效率。如Matrix + Matrix 返回一个代理类Sum<Matrix, Matrix>。
在源代码中很难隐藏,所以可以通过以下方式识别代理:
namespace std {
template<class Allocator>
class vector<bool, Allocator> {
public:
class reference {};
reference operator[](size_type n);
};
} // 返回了reference类型
可以使用显式类型初始化语句(explicitly typed initializer idiom)方式使用auto:
auto highPriority = static_cast<bool>(features(w)[]);
总结
- “不可见”的代理类型会导致auto推断初始化表达式时出现错误的类型
- 显式类型初始化语句强制auto推断为你想要的类型