Смежный адаптер с использованием boost :: range - PullRequest
0 голосов
/ 28 июня 2018

Я спрашиваю себя, можно ли расширить boost-range с помощью адаптера, который я называю adjacentAdaptor. Этот адаптер должен в основном перебирать все пары смежных элементов в vector, list и т. Д.

Я думаю, что эта функция очень полезна в моих случаях использования, когда мне часто приходится повторять списки, представляющие временные шаги.

Вывод последнего цикла for должен выглядеть примерно так:

0 1
1 2
2 3

Вектор, имеющий только один элемент или не содержащий элементов, ничего не должен производить.

Я пытался использовать boost::adaptors::sliced для создания необходимого подсписка, но тогда я не знаю, как boost::range может помочь мне сжать оба поддиапазона в один.

Я только что нашел вероятное решение, используя boost::iterators, но мне действительно не нравится объем кода, который нужно написать. Также мне не хватает first и second, вместо этого я должен написать неуклюжий get<>. К сожалению, программа вылетает, если вектор пуст!

#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>

int main()
{
        std::vector<int> v = { 0,1,2,3 };
        for (auto iter : v | boost::adaptors::sliced(0, v.size() - 1)) {
            std::cout << "First: " << iter << std::endl;
        }
        for (auto iter : v | boost::adaptors::sliced(1, v.size())) {
            std::cout << "Second: "<< iter << std::endl;
        }
        auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.begin(), v.begin() + 1));
        auto e = boost::iterators::make_zip_iterator(boost::make_tuple(v.end()-1, v.end()));
        for (auto iter : boost::make_iterator_range(s, e)) {
            std::cout << iter.get<0>() << " " << iter.get<1>() << std::endl;
        }
//          for (auto iter : v | adjacentAdaptor) {
//              std::cout << iter.first << " " << iter.second << std::endl;
//          }
}

Я очень рад любой помощи, которую я могу получить в этом вопросе.

Собственное частичное решение

После некоторого вывода типа шаблона я нашел кое-что относительно полезное.

#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>

template<typename T>
using retHelperType = decltype(boost::iterators::make_zip_iterator(boost::make_tuple(T().begin(), T().begin() + 1)));

template<typename T>
using retType = decltype(boost::make_iterator_range(retHelperType<T>(), retHelperType<T>()));

template<typename T>
retType<T> adjacentIterator(T& v) {
    if (v.empty()) {
        auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.end(), v.end()));
        auto e = boost::iterators::make_zip_iterator(boost::make_tuple(v.end(), v.end()));
        return boost::make_iterator_range(s, e);
    }
    else {
        auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.begin(), std::next(v.begin())));
        auto e = boost::iterators::make_zip_iterator(boost::make_tuple(std::prev(v.end()), v.end()));
        return boost::make_iterator_range(s, e);
    }
}

int main()
{
    retType<std::vector<int>> x;
    std::vector<int> v = { };

    for (auto iter : adjacentIterator(v)) {
        std::cout << iter.get<0>() << " " << iter.get<1>() << std::endl;
    }
}

Тем не менее, было бы лучше получить доступ к элементам с first и second, но я понятия не имею, как добиться такого поведения.

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