以std::sort
和std::ranges::sort
为例,中的迭代器类std::ranges::sort
受到以下概念的约束std::random_access_iterator
:
template< std::random_access_iterator I, std::sentinel_for<I> S,
class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I
sort( I first, S last, Comp comp = {}, Proj proj = {} );
但std::sort
不是:
template< class RandomIt >
void sort( RandomIt first, RandomIt last );
为什么std::sort
(以及所有非范围算法)不受限制?
当然有实际和历史的原因;但如果想想事后原因:
否则,你会破坏很多代码;范围样式的要求比你想象的要严格得多。有很多现成的代码(自定义迭代器)几乎是偶然与算法一起工作的,而且绝对不会与
std::ranges
算法一起编译。std::ranges
以indirectly_writable
https://en.cppreference.com/w/cpp/iterator/indirectly_writable中的一个常见要求为例。我敢打赌,Concepts 之前编写的几乎所有非平凡迭代器实际上都无法满足所有施加的约束。它是“受约束的”,但不是概念意义上的:
[算法.要求]p(4.7)
这个“必须”要求可以在您的 C++ 标准库中进行测试
static_assert
(并且一直能够这样做)。如果标准库实现者寻找实际上未使用的内容,那么这只是一个实现质量问题。这与概念约束参数不同,其中函数不参与重载解析。
您可以看到,对于多个重载(范围或迭代器对)和默认参数,在调用时选择正确的函数是多么必要。
对于只有一个重载的非范围算法来说,这不是必需的。具有多个重载的算法将执行策略作为第一个参数,而第二个重载本质上是概念约束的([algorithms.parallel.overloads]p4)