如何压缩(组合迭代器)无法处理boost :: prior的方法

时间:2018-07-06 09:35:34

标签: c++ boost iterator range

我有以下代码来生成范围内相邻对的元组。这适用于双向范围,但不适用于仅向前范围。

    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 不接受带有正向范围的范围。是否有同样适用于前进范围的优雅解决方案?

boost::combine

2 个答案:

答案 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);
}

Live On Coliru

#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

也许做一个迭代器适配器会更好。