HighCommander4
HighCommander4

Reputation: 52739

Boost.Range algorithm for getting the nth element of a range

Is there a way to get the n'th element of a range using Boost.Range? (I am not talking about the nth_element algorithm which returns the element that would be in n'th position if the range were sorted. I simply want the n'th element according to the current order of elements in the range).

I would expect this function to work on both forward and random-access ranges (being linear-time in the case of forward ranges and constant time in the case of random-access ranges), and to throw an exception (std::out_of_range perhaps) if the range has fewer than n elements.

I know this can by std::advance-ing the begin() iterator of the range by n, but I'm looking for a range-based solution which doesn't descend to the level of iterators.

EDIT: Actually, this can't be done with std::advance because std::advance doesn't check if you're going past the end of the range.

Upvotes: 2

Views: 1536

Answers (2)

Apivan Tuntakurn
Apivan Tuntakurn

Reputation: 160

I encountered the similar issue. I solved it using boost::adaptor::strided.

Upvotes: 0

ildjarn
ildjarn

Reputation: 62975

I don't see anything like that built in, but it seems pretty easy to implement:

namespace details {

template<typename RangeT, typename IterCatT>
typename boost::range_reference<RangeT>::type nth_impl(
    RangeT& range,
    typename boost::range_difference<RangeT>::type n,
    IterCatT const)
{
    typedef typename boost::range_iterator<RangeT>::type iter_t;

    iter_t first = boost::begin(range), last = boost::end(range);
    while (n--)
        if (++first == last)
            throw std::range_error("n");
    return *first;
}

template<typename RangeT>
typename boost::range_reference<RangeT>::type nth_impl(
    RangeT& range,
    typename boost::range_difference<RangeT>::type const n,
    std::random_access_iterator_tag const)
{
    if (boost::size(range) <= n)
        throw std::range_error("n");

    return *(boost::begin(range) + n);
}

}

template<typename RangeT>
typename boost::range_reference<RangeT>::type nth(
    RangeT& range,
    typename boost::range_difference<RangeT>::type const n)
{
    return details::nth_impl(
        range,
        n,
        typename boost::range_category<RangeT>::type()
    );
}

Upvotes: 2

Related Questions