如何创建类似于“范围"的浮动对象? [英] How to create a `range`-like iterable object of floats?

查看:74
本文介绍了如何创建类似于“范围"的浮动对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在,将像这样使用:

I want to create a range-like construct in c++, that will be used like this:

for (auto i: range(5,9))
    cout << i << ' ';    // prints 5 6 7 8 

for (auto i: range(5.1,9.2))
    cout << i << ' ';    // prints 5.1 6.1 7.1 8.1 9.1

处理整数情况相对容易:

Handling the integer case is relatively easy:

template<typename T>
struct range 
{
    T from, to;
    range(T from, T to) : from(from), to(to) {}

    struct iterator
    {
        T current;
        T operator*() {  return current; }

        iterator& operator++()
        {
            ++current;
            return *this;
        }

        bool operator==(const iterator& other) { return current == other.current; }
        bool operator!=(const iterator& other) { return current != other.current; }
    };

    iterator begin() const { return iterator{ from }; }
    iterator end()   const { return iterator{ to }; }
};

但是,这在float情况下不起作用,因为C++中的基于范围的标准循环会检查是否iter==end,而不是是否像循环那样检查iter <= end.

However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end and not whether iter <= end as you would do in a for a loop.

是否有一种简单的方法来创建一个可迭代对象,该对象的行为类似于在float s上基于正确的 range for循环的行为?

Is there a simple way to create an iterable object that will behave like a correct range based for-loop on floats?

推荐答案

这是我的尝试,不损害迭代器的语义.现在,每个迭代器都知道其停止值.迭代器将在超过该值时将自身设置为该值.因此,范围to相等的所有最终迭代器都相等.

Here is my attempt which does not impair the semantics of iterators. Now, each iterator knows its stopping value. The iterator will set itself to this value upon exceeding it. All end iterators of a range with equal to therefore compare equal.

template <typename T> 
struct range {
    T from, to;
    range(T from, T to): from(from), to(to) {}

    struct iterator {
        const T to; // iterator knows its bounds
        T current;

        T operator*() { return current; }

        iterator& operator++() { 
            ++current;
            if(current > to)
                // make it an end iterator
                // (current being exactly equal to 'current' of other end iterators)
                current = to;
            return *this;
        }

        bool operator==(const iterator& other) const // OT: note the const
        { return current == other.current; }
        // OT: this is how we do !=
        bool operator!=(const iterator& other) const { return !(*this == other); }
    };

    iterator begin() const { return iterator{to, from}; }
    iterator end()   const { return iterator{to, to}; }
};

为什么这样更好?

@JeJo的解决方案取决于您比较这些迭代器的顺序,即it != endend != it.但是,在基于范围的情况下,已定义.如果您在其他情况下使用此工具,我建议您采用上述方法.

Why is this better?

The solution by @JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.

或者,如果为sizeof(T) > sizeof(void*),则有必要存储指向始发range实例的指针(在range-for的情况下一直持续到结束),并使用该指针来引用单个T值:

Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:

template <typename T> 
struct range {
    T from, to;
    range(T from, T to): from(from), to(to) {}

    struct iterator {
        range const* range;
        T current;

        iterator& operator++() { 
            ++current;
            if(current > range->to)
                current = range->to;
            return *this;
        }

        ...
    };

    iterator begin() const { return iterator{this, from}; }
    iterator end()   const { return iterator{this, to}; }
};

或者可能是T const* const直接指向该值,这取决于您.

Or it could be T const* const pointing directly to that value, it is up to you.

OT:别忘了为这两个类制作内部零件private.

OT: Do not forget to make the internals private for both classes.

这篇关于如何创建类似于“范围"的浮动对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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