【问题标题】:Boost.Range algorithm for getting the nth element of a range用于获取范围的第 n 个元素的 Boost.Range 算法
【发布时间】:2011-06-21 21:57:13
【问题描述】:

有没有办法使用 Boost.Range 获取范围的第 n 个元素? (我不是在谈论 nth_element 算法,如果对范围进行排序,该算法将返回第 n 个位置的元素。我只想要根据当前顺序的第 n 个元素范围内的元素)。

我希望这个函数能够在前向和随机访问范围上工作(在前向范围的情况下是线性时间,在随机访问范围的情况下是恒定时间),并抛出异常 (@987654322 @ 可能)如果范围内的元素少于 n

我知道这可以通过std::advance-ing 范围的begin() 迭代器通过n,但我正在寻找一种不会下降到迭代器级别的基于范围的解决方案。

编辑:实际上,std::advance 无法做到这一点,因为 std::advance 不会检查您是否超出范围的末尾。

【问题讨论】:

  • @yi_H: std::advance 不会检查您是否超出范围的末尾(因为它不知道结束迭代器)。如果发生这种情况,我希望抛出异常。
  • “但我正在寻找一种不会下降到迭代器级别的基于范围的解决方案” - 最后,它当然会下降到迭代器。
  • @Xeo:当然,就像 STL 最终下降到指针级别一样。但是我们不想在可以避免的情况下在指针级别进行编程,对吧?
  • 好吧,一旦你写了那个函数,你就完成了。您需要编写与图层交互的代码。
  • @Xeo:我知道。我只是想知道 Boost.Range 中是否有一些东西已经做到了。

标签: c++ boost range


【解决方案1】:

我没有看到类似的内置功能,但它似乎很容易实现:

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()
    );
}

【讨论】:

  • 这将不必要地遍历前向范围两次。
  • @HighCommander4 :boost::size 的理智专业化,例如一个知道自己大小但提供非随机访问迭代器的容器将使用该容器的 size 成员函数。即,在任何合理的情况下,调用 boost::size 将不涉及任何遍历。
  • 是的,但即使对于不知道其大小的前向范围(例如std::forward_list,或通过filtered 适配器的任何范围),也没有必要遍历两次 - 你可以推进迭代器并检查它是否同时到达末尾。
  • @HighCommander:好吧,如果你想为每次迭代的检查付出代价。
  • @HighCommander4 :答案已编辑,但这看起来确实像是您可以自己完成的事情。 ;-]
【解决方案2】:

我遇到了类似的问题。我使用boost::adaptor::strided 解决了它。

【讨论】:

    猜你喜欢
    • 2012-09-25
    • 2011-01-24
    • 2021-10-28
    • 2023-03-13
    • 2016-07-07
    • 2010-10-16
    • 1970-01-01
    • 2012-02-02
    相关资源
    最近更新 更多