C++20范围适配器的begin/end的const重载是否存在约束不足问题?
结论先行
这是C++20范围适配器规范的标准缺陷,你构造的weird_range本身完全符合标准对range的要求,不存在不合法的问题。
成因分析
标准在设计范围适配器的const限定begin()/end()时,隐含了一个从未明确写入规范的假设:如果const V是range,那么它的所有核心特性(是否为common_range、迭代器类别、值类型、迭代器/哨兵类型等)都和非const的V保持一致,仅在访问权限上多了const限定。
但标准从来没有强制要求range的const和非const版本行为一致,所以你构造的这种两类版本特性差异极大的range是完全合法的,这就触发了现有约束的漏洞:
- 以
common_view为例,类模板层面要求V不是common_range,但begin() const的约束仅检查const V满足range概念,完全没有校验const V是否符合类模板对底层范围的要求 - 当
const V本身就是common_range,甚至迭代器/哨兵类型和非const版本完全不兼容时,common_view的begin() const内部逻辑(将底层迭代器和哨兵包装为common_iterator)就会触发硬错误,你给出的代码示例就是典型的触发场景 - 同理
reverse_view、elements_view这类适配器的const begin/end都存在相同的约束过松问题,只检查const V是range完全不足以保证内部逻辑合法。
修复方向
这类问题已经被纳入LWG issue的修复序列,你提到的LWG 3592、LWG 3599就是同类型缺陷的修复案例。正确的约束规则应该是:范围适配器的const begin/end需要将类模板对底层范围V的所有约束,全部同步应用到const V上,而不是仅检查const V是range。
比如对common_view来说,begin() const的约束应该调整为:
constexpr auto begin() const requires range<const V> && !common_range<const V> && copyable<iterator_t<const V>>;
和类模板层面的约束完全对齐,就能避免这类边界错误。
补充说明
你观察到的“标准似乎不关心V和const V差异极大的场景”只是现阶段的疏漏:绝大多数常规业务场景实现的range,const和非const版本的特性都是一致的,这类边界问题只有在极端自定义range下才会触发,所以标准编写初期没有覆盖到这类情况,后续的标准迭代会逐步补全相关约束。
内容的提问来源于stack exchange,提问作者康桓瑋
相关产品推荐
相关产品推荐

