如果我有范围(一对 2 个迭代器),有没有办法为使用范围而不是原始数组或容器编写“for each”循环。
像这样的东西:
auto rng = std::equal_range(v.begin(),v.end(),1984);
for(const auto& elem: rng) {
// ...
}
根据为什么从 C++11 中删除了对范围访问?您可以使用适配器,例如as_range
at 接受的答案boost::make_iterator_range
,或编写您自己的:
template<typename It> struct range {
It begin_, end_;
It begin() const { return begin_; }
It end() const { return end_; }
};
template<typename It> range<It> as_range(const std::pair<It, It> &p) {
return {p.first, p.second};
}
auto rng = std::equal_range(v.begin(),v.end(),1984);
for(const auto& elem: as_range(rng))
...
这通常不适用的原因是,根据Alastair Meredith 的论文,算法,
mismatch
并partition_copy
返回一对来自不同范围的迭代器;minmax
返回一对可能根本不是迭代器的对象,如果它们是,则不能保证它们形成一个范围;minmax_element
可以返回一个范围,但它也可以返回一个反向范围(例如,在反向排序的范围minmax_element
上将返回{prev(last), first}
;equal_range
保证返回一个范围。我不认为它会像返回一对迭代器一样开箱即用地工作equal_range
,而根据文档的 for 循环范围是:
The begin_expr and end_expr are defined to be either:
If (__range) is an array, then (__range) and (__range + __bound), where __bound is the array bound
If (__range) is a class and has either a begin or end member (or both), then begin_expr is __range.begin() and end_expr is __range.end();
Otherwise, begin(__range) and end(__range), which are found based on argument-dependent lookup rules with std as an associated namespace.
我想说你可以定义begin
和end
函数来接受这对迭代器并分别返回第一个和第二个。
#include <vector>
#include <algorithm>
#include <iostream>
template <typename I>
struct range_adapter {
std::pair<I, I> p;
range_adapter(const std::pair<I, I> &p) : p(p) {}
I begin() const { return p.first; }
I end() const { return p.second; }
};
template <typename I>
range_adapter<I> in_range(const std::pair<I, I> &p)
{
return range_adapter<I>(p);
}
int main()
{
std::vector<int> data { 1, 2, 2, 3, 3, 3, 4 };
auto r = std::equal_range(data.begin(), data.end(), 2);
for (const auto &elem : in_range(r))
{
std::cout << elem << std::endl;
}
}
std::equal_range
返回的只是一个 std::pair 。该标准不涵盖任何迭代此类事物的方法。
您可能想阅读的是 Alexandrescu 的“Iterators must go”演示文稿。这是视频。关于使用 Ranges 迭代容器的更优雅方式的优秀读物。
范围在他的Loki库中实现。