我有以下代码来生成范围内相邻对的元组。这适用于双向范围,但不适用于仅向前范围。
template <typename Range>
// Returns a range of adjacent pairs of the input range
auto make_adjacent_range(Range const & r) -> decltype(boost::combine(
boost::make_iterator_range(boost::begin(r), boost::prior(boost::end(r))),
boost::make_iterator_range(boost::next(boost::begin(r)), boost::end(r))))
{
return boost::combine(
boost::make_iterator_range(boost::begin(r), boost::prior(boost::end(r))),
boost::make_iterator_range(boost::next(boost::begin(r)), boost::end(r)));
}
boost :: prior 不接受带有正向范围的范围。是否有同样适用于前进范围的优雅解决方案?
答案 0 :(得分:2)
不太优雅,但是您可以只写一个adjacent_iterator
类型。
使它适用于InputIterator
相对比较棘手,因为您必须在每次递增之前都取消引用
template <typename InputIterator>
class adjacent_iterator
{
public:
using element_type = std::iterator_traits<InputIterator>::value_type;
using value_type = std::pair<element_type, element_type>;
using category = std::iterator_traits<InputIterator>::category;
// all the other typedefs
adjacent_iterator& operator++()
{
element.first = element.second;
if (needs_deref) element.second = *it;
++it;
needs_deref = true;
return *this;
}
reference operator*()
{
element.second = *it;
needs_deref = false;
return element;
}
// all the other members
friend bool operator==(adjacent_iterator lhs, adjacent_iterator rhs)
{
// only check the iterator
return lhs.it == rhs.it;
}
private:
adjacent_iterator(element_type first, InputIterator second)
: element(first, {}), it(second), needs_deref(true) {}
adjacent_iterator(InputIterator end)
: it(end) {}
InputIterator it;
value_type element;
bool needs_deref;
// not sure how to declare this friendship
template <typename Range>
friend auto make_adjacent_range(Range const & r)
{
auto begin = boost::begin(r);
auto end = boost::end(r);
using IT = decltype(boost::begin(r));
auto elem = *begin++;
auto b = adjacent_iterator<IT>(elem, begin);
auto e = adjacent_iterator<IT>(end);
return boost::make_iterator_range(b, e);
}
};
答案 1 :(得分:1)
这可行,但根据迭代器类型的不同,效率可能很低:
template <typename Range>
auto make_adjacent_range(Range const & r) {
auto n = boost::size(r);
auto b = boost::begin(r);
auto r1 = boost::make_iterator_range(b, boost::next(b, n-1));
auto r2 = r1;
r2.advance_begin(1);
r2.advance_end(1);
return boost::combine(r1, r2);
}
#include <boost/range.hpp>
#include <boost/range/combine.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <iostream>
#include <forward_list>
template <typename Range>
auto make_adjacent_range(Range const & r) {
auto n = boost::size(r);
auto b = boost::begin(r);
auto r1 = boost::make_iterator_range(b, boost::next(b, n-1));
auto r2 = r1;
r2.advance_begin(1);
r2.advance_end(1);
return boost::combine(r1, r2);
}
int main() {
std::forward_list<int> v{1,2,3,4};
for (auto p : make_adjacent_range(v))
std::cout << p.get<0>() << " " << p.get<1>() << "\n";
}
打印
1 2
2 3
3 4
也许做一个迭代器适配器会更好。