仅在基于范围的循环中对奇数(偶数)元素进行迭代 [英] Iterating over odd (even) elements only in a range-based loop

查看:64
本文介绍了仅在基于范围的循环中对奇数(偶数)元素进行迭代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个普通数组(或其他支持基于范围的循环的容器):

Suppose we have a plain array (or other container which supports 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 and increment 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 by using a range-based loop and avoiding explicit iterators/indexes and iteration skipping? Something like this:

for (const auto& v: odd_only(arr))
{
   std::cout << v << std::endl;
}

一个简单而优雅的解决方案是什么样的?标准库是否包含这样的内容?

What does a simple and elegant solution look like? Does the standard library contain something like this?

推荐答案

您所请求的内容不支持–但是您可以编写自己的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆