这就是我要做的。
#include <iterator>
#include <utility>
template <typename FwdIt> class adjacent_iterator {
public:
adjacent_iterator(FwdIt first, FwdIt last)
: m_first(first), m_next(first == last ? first : std::next(first)) { }
bool operator!=(const adjacent_iterator& other) const {
return m_next != other.m_next; // NOT m_first!
}
adjacent_iterator& operator++() {
++m_first;
++m_next;
return *this;
}
typedef typename std::iterator_traits<FwdIt>::reference Ref;
typedef std::pair<Ref, Ref> Pair;
Pair operator*() const {
return Pair(*m_first, *m_next); // NOT std::make_pair()!
}
private:
FwdIt m_first;
FwdIt m_next;
};
template <typename FwdIt> class adjacent_range {
public:
adjacent_range(FwdIt first, FwdIt last)
: m_first(first), m_last(last) { }
adjacent_iterator<FwdIt> begin() const {
return adjacent_iterator<FwdIt>(m_first, m_last);
}
adjacent_iterator<FwdIt> end() const {
return adjacent_iterator<FwdIt>(m_last, m_last);
}
private:
FwdIt m_first;
FwdIt m_last;
};
template <typename C> auto make_adjacent_range(C& c) -> adjacent_range<decltype(c.begin())> {
return adjacent_range<decltype(c.begin())>(c.begin(), c.end());
}
#include <iostream>
#include <vector>
using namespace std;
void test(const vector<int>& v) {
cout << "[ ";
for (const auto& p : make_adjacent_range(v)) {
cout << p.first << "/" << p.second << " ";
}
cout << "]" << endl;
}
int main() {
test({});
test({11});
test({22, 33});
test({44, 55, 66});
test({10, 20, 30, 40});
}
这打印:
[ ]
[ ]
[ 22/33 ]
[ 44/55 55/66 ]
[ 10/20 20/30 30/40 ]
笔记:
我没有对此进行详尽的测试,但它尊重前向迭代器(因为它不会尝试使用 ++、!= 和 * 之外的操作)。
range-for 的要求极弱;它不需要转发迭代器应该提供的所有东西。因此,我已经达到了 range-for 的要求,但仅此而已。
“NOT m_first”注释与如何接近范围末端有关。从空范围构造的相邻迭代器具有 m_first == m_next,它也是 == last。从 1 元素范围构造的相邻迭代器具有 m_first 指向该元素和 m_next == 最后。从多元素范围构造的相邻迭代器具有指向连续有效元素的 m_first 和 m_next。随着它的增加,最终 m_first 将指向最后一个元素,而 m_next 将是最后一个。next_range 的 end() 返回的内容是从 (m_last, m_last) 构造的。对于一个完全空的范围,这在物理上与 begin() 相同。对于 1+ 元素范围,这在物理上与 begin() 不同,它在我们不做之前一直递增 t 有一个完整的对 - 这样的迭代器有 m_first 指向最后一个元素。但是如果我们根据它们的 m_next 比较迭代器,那么我们会得到正确的语义。
“NOT std::make_pair()”注释是因为 make_pair() 衰减,而我们实际上想要一对引用。(我本可以使用 decltype,但 iterator_traits 也会告诉我们答案。)
剩下的主要微妙之处在于禁止将右值作为 make_adjacent_range 的输入(这样的临时人员不会延长他们的生命;委员会正在研究这个问题),并播放 ADL 舞蹈以尊重非成员的开始/结束,以及内置 -在数组中。这些练习留给读者。