Как использовать итераторы boost::range со стандартными итераторами

У меня есть функции, которые принимают std::vector итераторов, например

typedef std::vector<Point> Points;

Points ConvexHull(Points::const_iterator first, Points::const_iterator last);

Обычно я передаю им итераторы std, но иногда мне нужно работать с итераторами boost, такими как итератор диапазона boost::join. Как мне изменить параметризации моих функций, в идеале без шаблонов, чтобы они принимали оба итератора? Более того, как указать в каждом типе, какие концепции итераторов мне нужны?

Я попытался просмотреть документацию boost::range, но она меня очень сбивает с толку, и я не знаю, с чего начать.

Например, я не мог найти разницу между boost::range_details::any_forward_iterator_interface и boost::range_details::any_forward_iterator_wrapper и не мог использовать любой из них, чтобы указать, что мне нужен прямой итератор.


Изменить:

Если я использую boost::any_range, как я могу передавать неконстантные ссылки lvalue?

Например:

template<typename T>
using Range = boost::any_range<T, boost::random_access_traversal_tag, 
                               T, std::ptrdiff_t>;


f(Range<Point> &points);  // defined elsewhere

// -------------

vector<Point> vec;
f(vec);  // error; cannot bind non-const lvalue reference to unrelated type

person Anakhand    schedule 19.03.2019    source источник


Ответы (2)


Вы должны настоятельно рассмотреть возможность использования шаблона. Это позволяет компилятору сохранять полезную информацию о том, какие операции выполняются на самом деле, что очень помогает ему генерировать оптимизированный вывод. Соглашение std:: заключается в том, чтобы назвать параметр типа для требуемой концепции. Например.

template< class BidirIt, class UnaryPredicate > // anything bidirectional (which includes random access)
BidirIt std::partition( BidirIt first, BidirIt last, UnaryPredicate p );

Если вам действительно не нужен шаблон, вы все равно ничего не должны называть в пространстве имен detail. Что-то вроде

#include <boost/range/any_range.hpp>

using PointRange = boost::any_range<Point, boost::random_access_traversal_tag>; // or another traversal tag.
using PointIterator = PointRange::iterator;

Скорее всего, вам придется проходить PointRange & реже, чем, скажем, int *&. Почти всегда передача по значению является правильным поведением. Его дешево копировать, так как он содержит итератор begin и end из Range, из которого он был создан, не более того.

person Caleth    schedule 19.03.2019

boost-range имеет any_range для этой цели, и это подходит для обеих целей для вашего случая.

https://www.boost.org/doc/libs/1_60_0/libs/range/doc/html/range/reference/ranges/any_range.html

Из вашего примера это будет выглядеть так:

#include <boost/range/any_range.hpp>

typedef boost::any_range<Point,
                         boost::bidirectional_traversal_tag,
                         Point,
                         std::ptrdiff_t
                        > PointRange;
person darune    schedule 19.03.2019
comment
Спасибо! Да, я верю, что это то, что я ищу. Но есть ли способ получить доступ к диапазону size? Кажется, что size не определено для boost::any_range<Point, boost::bidirectional_traversal_tag, Point, std::ptrdiff_t>; - person Anakhand; 19.03.2019
comment
Вы можете использовать бесплатную функцию boost::size - person Caleth; 19.03.2019
comment
просто позвони boost::size(range) - person darune; 19.03.2019
comment
Спасибо! И есть ли способ передать неконстантные ссылки lvalue? (см. правку выше) - person Anakhand; 19.03.2019
comment
@Anakhand это больше похоже на С++, чем на boost::range - это невозможно, если ваш вектор не имеет типа диапазона (т.е. наследования) - вам нужно каким-то образом создать объект диапазона, то есть удалить ссылку - мне нравится думайте о диапазоне как о паре итераторов. - person darune; 19.03.2019