如何创建类似于“范围"的浮动对象? [英] How to create a `range`-like iterable object of floats?
问题描述
我想在range的结构"tag"> c ++ ,将像这样使用:
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 float
s?
推荐答案
这是我的尝试,不损害迭代器的语义.现在,每个迭代器都知道其停止值.迭代器将在超过该值时将自身设置为该值.因此,范围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 != end
或end != 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屋!