仅在基于范围的循环中对奇数(偶数)元素进行迭代 [英] Iterating over an odd (even) elements only in a range-based loop
问题描述
假设我们有一个普通数组(或其他支持基于范围的循环的容器):
Suppose we have a plain array (or other container which support range based loops):
const int N = 8;
int arr[N] = {0, 1, 2, 3, 4, 5, 6, 7};
使用索引或迭代器,我们可以遍历奇数元素,使索引增加两个:
Using indexes or iterators we can loop over odd elements increasing the index by two:
for (int i = 0; i < N; i+=2)
{
std::cout << arr[i] << std::endl;
}
如何使用基于范围的循环并避免显式的迭代器获得类似的结果/索引或迭代跳过用法?
How can I get a similar result using range based loop and avoiding explicit iterators/indexes or iteration skipping usage? Something like:
for (const auto& v: odd_only(arr))
{
std::cout << v << std::endl;
}
您看到什么简单而优雅的解决方案?标准库中是否包含类似的内容?
What the simple and elegant solution do you see? Does the Standard Library contain something like that?
推荐答案
您的请求不支持–但是您可以编写自己的 even_only
和 odd_only
实现。
There's no support for what you request – but you might write your own even_only
and odd_only
implementations.
基本思想是包装有问题的容器的普通迭代器,并在每次外部递增一次时在内部进行两次递增:
Basic idea is to wrap around the normal iterator of the container in question and do a double increment internally each time we increment once externally:
template <typename C, bool IsOdd>
class even_odd_only
{
C& c;
public:
class iterator
{
public:
// all the definitions required for iterator!
// most if not all might simply be derived from C::iterator...
// copy/move constructor/assignment as needed
// core of the wrapper: increment twice internally!
// just doing += 2 is dangerous, though, we might increment beyond
// the end iterator (undefined behaviour!)additionally, += 2 only
// is possible for random access iterators (so we limit usability)
void operator++() { ++b; if(b != e) ++b; }
// operator* and operator-> (both return *b), post-increment
// (defined in terms of pre-increment), etc...
// comparison: only needs to compare b iterators!
private:
C::iterator b;
C::iterator e; // needed for comparison to avoid incrementing beyond!
iterator(C::iterator b, C::iterator e) : b(b), e(e) { }
};
// const_iterator, too; possibly make a template of above
// and derive const and non-const iterators from?
even_odd_only(C& c) : c(c) { }
iterator begin()
{
using std::begin;
using std::end;
using std::empty;
auto b = begin(c);
// should be self-explanatory:
// skip first element in odd variant (if there is)
if constexpr(IsOdd) { if(!empty(c)) { ++b; } }
return iterator(b, end(c));
};
iterator end()
{
using std::end;
return iterator(end(c), end(c));
}
};
template <typename T>
using even_only = even_odd_base<T, false>;
template <typename T>
using odd_only = even_odd_base<T, true>;
按原样,它甚至可以用于非随机访问甚至非双向迭代器。但是特别是对于RA迭代器,它的效率不如经典循环(由于在 operator ++
中处于中间状态,因此)。
As is, it would work even with non-random-access and even non-bidirectional iterators. But especially for RA-iterators, it's less efficient than the classic loop (due to the intermediate if in operator++
).
定义比较迭代器:总是 operator ==
和 operator!=
,仅对于随机访问运算符,您可以另外拥有 operator [<||> |< = |&=; =]
(→ std :: enable_if
)
Defining comparison iterators: always operator==
and operator!=
, only for random access operators you can additionally have operator[<|>|<=|>=]
(→ std::enable_if
).
您将找到有关如何编写迭代器的更多详细信息此处–不过,请记住, std :: iterator
本身已被弃用。
You'll find more details about how to write an iterator here – keep in mind when you encounter, though, that std::iterator
itself is deprecated now.
这篇关于仅在基于范围的循环中对奇数(偶数)元素进行迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!