Я спрашиваю себя, можно ли расширить 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
, но я понятия не имею, как добиться такого поведения.