为何iter_const_reference_t不直接使用std::add_const_t实现?
iter_const_reference_t采用common_reference_t实现而非直接用add_const_t<std::iter_reference_t<T>>? 给定两种实现方式:
标准实现:
template<std::indirectly_readable T> using iter_const_reference_t = std::common_reference_t<const std::iter_value_t<T> &&, std::iter_reference_t<T>>;
替代写法:
template<std::indirectly_readable T> using iter_const_reference_t = std::add_const_t<std::iter_reference_t<T>>;
为什么标准不采用后者?原因主要有三点:
值类型引用的场景处理错误
如果std::iter_reference_t<T>是值类型(比如某些特殊迭代器返回值而非引用),add_const_t会直接得到const T——这是一个const值类型,而非我们需要的“指向迭代器元素的const引用”。而common_reference_t<const T&&, T>会推导出const T&,这才是符合语义的“对元素的只读引用”类型。代理迭代器的适配问题
像std::vector<bool>的迭代器这类代理迭代器,它的iter_reference_t是代理对象(比如std::vector<bool>::reference),而非原生的bool&。此时add_const_t只会给代理对象加上const限定,得到const std::vector<bool>::reference,这和const bool&不是同一类型,无法正确表示对底层bool值的只读引用。而common_reference_t<const bool&&, std::vector<bool>::reference>会推导出const bool&,完美匹配我们需要的“只读引用”语义。移动迭代器的语义修正
对于移动迭代器,std::iter_reference_t<T>是T&&(右值引用)。add_const_t会得到const T&&——这种const右值引用几乎没有实用意义,因为它既不能修改对象,也无法高效移动。而common_reference_t<const T&&, T&&>会推导出const T&,这才是合理的只读引用类型,既能安全访问对象,又符合const引用的通用语义。
内容的提问来源于stack exchange,提问作者Martin Fehrs

