Как сжать (объединить итераторы), которые не поддерживают boost :: prior - PullRequest
0 голосов
/ 06 июля 2018

У меня есть следующий код для генерации кортежей соседних пар в диапазоне. Это работает для двунаправленных диапазонов, но не только для форвардов дальнего боя.

    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 :: previous не принимается с диапазоном только вперед. Есть ли такое же элегантное решение, которое будет работать с передовыми диапазонами?

подталкивание :: скомбинировать

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Не очень элегантно, но вы можете просто написать тип 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);
    }
};
0 голосов
/ 06 июля 2018

Это работает, но может быть довольно неэффективно в зависимости от типов итераторов:

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

Возможно, было бы лучше сделать адаптер итератора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...