C++23中仍无法对以pair为值/引用类型的代理迭代器范围排序?
pair异构比较缺失的疑问 尽管P2321为zip给pair提供了common_reference特化,且P2165《tuple、pair与类tuple对象的兼容性》实现了tuple与pair的互转,但在[pairs.spec]中,pair的比较函数仅提供同构版本:
template<class T1, class T2> constexpr common_comparison_category_t<...> operator<=>(const pair<T1, T2>& x, const pair<T1, T2>& y);
该版本仅支持模板参数完全一致的pair比较,因此无法比较不同类型的pair,例如:
using value_type = pair<int , string >; using reference = pair<int&, string&>; value_type val = {1, "a"}; reference ref = val; val < ref; // 无匹配的'operator<'
这直接导致以pair作为value_type/reference的代理迭代器无法满足sortable概念——该概念要求iter_value_t<I>必须能与iter_reference_t<I>比较,进而使得ranges::sort无法作用于这类迭代器(比如P2165之前的zip_view::iterator),除非手动传入自定义比较器:
std::vector<int> x, y; ranges::sort(std::views::zip(x, y)); // P2165之前无法正常工作 // 因为zip_view的引用类型是pair<int&, int&>,无法与其值类型pair<int, int>比较 // P2165之后引用类型改为tuple<int&, int&>,就能正常工作 // 因为tuple支持与对应值类型的比较
为什么C++23未引入pair的异构比较?
这并非疏漏,而是标准委员会有意的设计选择,核心考量如下:
历史兼容性与歧义规避
异构比较的引入可能引发重载决议歧义。当存在隐式转换路径时,同构与异构比较的候选函数可能让编译器无法确定最佳匹配,破坏既有代码的稳定行为。已有替代方案
tuple
P2165已将zip_view的引用类型从pair改为tuple,而tuple本身支持异构比较(通过分别推导左右操作数的模板参数),足以满足代理迭代器的sortable需求。标准委员会认为,既然已有更通用的tuple作为解决方案,专门为pair添加异构比较的优先级较低。控制
pair的设计复杂度pair的设计目标是轻量化、接口简洁的二元组结构,引入异构比较会增加其接口复杂度。这类跨类型比较需求,完全可以通过tuple转换或自定义比较器实现,无需修改pair的核心接口。标准演进的优先级分配
C++23的核心特性集中在范围库完善、协程、模块化等方向,pair的异构比较不属于迫切需要解决的问题,因此未被纳入版本计划。
如果确实需要比较不同类型的pair,除了手动传入自定义比较器外,也可以将pair转换为tuple后利用其异构比较能力:
val < static_cast<tuple<int, string>>(ref); // 可行
内容的提问来源于stack exchange,提问作者康桓瑋

