考虑一个C可向前迭代的STL容器.我需要从每个step元素开始访问idx.如果C是向量(即具有随机访问迭代器),我可以使用索引算法:
template <class Container>
void go(const Container& C) {
for(size_t i = idx; i<C.size(); i+=step) {
/* do something with C[i] */
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如果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 */
}
}
Run Code Online (Sandbox Code Playgroud)
不会太长,它的工作原理......除了很可能它会触发未定义的行为.双方std::next并it+=step有可能步的方式超越了C.end()之前i < max执行检查.
我最初使用的解决方案(未显示)与初始化相比真的很臃肿.我对第一次迭代和后面的迭代进行了单独检查.很多样板代码......
所以,我的问题是,上述模式能否以安全,简洁的方式编写?想象一下,你想要将这些循环嵌套2到3次.你不想要整个代码页面!
std::next(C.begin(), i)在每次迭代过i是unnecessairly长,如果你可以std::advance(it, step)代替.it当std::advance可以在恒定时间内执行时,代码应该受益于确实是随机访问迭代器的情况.C是不变的.我不在C循环中插入,擦除或修改.Jar*_*d42 11
您可以使用辅助函数:
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{});
}
Run Code Online (Sandbox Code Playgroud)
然后:
for (auto it = secure_next(C.begin(), idx, C.end());
it != C.end();
it = secure_next(it, step, C.end()) {
/* do something with *it */
}
Run Code Online (Sandbox Code Playgroud)
或者,使用range-v3,您可以执行以下操作:
for (const auto& e : C | ranges::view::drop(idx) | ranges::view::stride(step)) {
/* do something with e */
}
Run Code Online (Sandbox Code Playgroud)
关于需求的问题中的注释激发了我实现这一点,k * step而不是控制容器上的迭代次数的其他机制.
template <class Container>
void go(const Container& C)
{
const size_t sz = C.size();
if(idx >= sz) return;
size_t k_max = (sz - idx) / step + 1;
size_t k = 0
for(auto it = std::advance(C.begin(), idx); k < k_max && (std::advance(it, step), true); ++k) {
/* do something with *it */
}
}
Run Code Online (Sandbox Code Playgroud)