c++ - 如何以简洁的方式安全地访问容器中的每个第 n 个元素?

标签 c++ c++11 stl

考虑一个 STL 容器 C这是可向前迭代的。我需要访问每个 step元素,从idx开始.如果C是一个 vector (即有一个随机访问迭代器)我可以只使用索引算法:

template <class Container>
void go(const Container& C) {
    for(size_t i = idx; i<C.size(); i+=step) {
        /* do something with C[i] */
    }
}

但是,如果 C不支持,例如C是一个列表,需要重写上面的解决方案。一个快速的尝试是:

template <class Container>
void go(const Container& C) {
    size_t max = C.size();
    size_t i = idx;
    for(auto it = std::next(C.begin(),idx); i < max; i+=step, it+=step) {
        /* do something with *it */
    }
}

没多久就可以了……除了它很可能会触发未定义的行为。两者 std::nextit+=step有可能超越C.end()之前 i < max执行检查。

与最初的 for 相比,我目前使用的解决方案(未显示)确实臃肿。我对第一次迭代和随后的迭代进行了单独检查。很多样板代码...

那么,我的问题是,上面的模式能否以安全、和简洁的方式编写?假设您想将这些循环嵌套 2 或 3 次。你不需要整页代码!

  • 代码应该足够短
  • 代码应该没有开销。做std::next(C.begin(), i)i 的每次迭代中不必要的长,如果你能的话std::advance(it, step)相反。
  • 代码应该受益于 it 的情况std::advance 时确实是一个随机访问迭代器可以在恒定时间内执行。
  • C是常数。我不插入、删除或修改 C在循环内。

最佳答案

您可以使用辅助函数:

template <typename IT>
IT secure_next(IT it, std::size_t step, IT end, std::input_iterator_tag)
{
    while (it != end && step--) {
        ++it;
    }
    return it;
}


template <typename IT>
IT secure_next(IT it, std::size_t step, IT end, std::random_access_iterator_tag)
{
    return end - it < step ? end : it + step;
}


template <typename IT>
IT secure_next(IT it, std::size_t step, IT end)
{
   return secure_next(it, step, end, typename std::iterator_traits<IT>::iterator_category{});
}

然后:

for (auto it = secure_next(C.begin(), idx, C.end());
     it != C.end();
     it = secure_next(it, step, C.end()) {
    /* do something with *it */
}

或者,使用 range-v3 ,你可以这样做:

for (const auto& e : C | ranges::view::drop(idx) | ranges::view::stride(step)) {
    /* do something with e */
}

关于c++ - 如何以简洁的方式安全地访问容器中的每个第 n 个元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45823347/

相关文章:

c++ - forward_list : assign(_InputIterator __first, _InputIterator __last)/assign(size_type __n, const _Tp& __val)

c++ - 成为左操作数意味着什么?

c++ - 数组指针永远不会出现段错误?

c++ - G++、clang++ 和 std::function

c++ - 根据 C++ 标准, `char* p=0; std::equal(p,p,p)` 是否定义明确?

c++ - 从 std::multimap<> 中删除项目后,我可以继续使用迭代器吗?

c++ - 命名空间中的 gcc 编译时错误排序 vector

c++ - clang std::isspace 编译错误

c++ - Linux 的 Qt 应用程序部署

c++ - 声明类型包含未扩展的参数包 'Args'