【发布时间】:2019-10-06 14:57:47
【问题描述】:
我想在c++ 中创建一个类似range 的构造,它将像这样使用:
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
处理整数情况相对容易:
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,就像您在for 循环中所做的那样。
有没有一种简单的方法来创建一个可迭代对象,它的行为类似于floats 上的正确基于范围的for-loop?
【问题讨论】:
-
可能是
operator==的特化,用于浮点类型,通过使用current<=other.current来颠覆语义? -
如何实现一个特殊的
end迭代器,当增量值超过to时将在operator++()中设置? -
既然提到了协程,为什么不使用即将到来的ranges library呢? (或者 the range library 是标准的基础?)
-
您应该知道浮点舍入会影响您的循环。例如,对于
double常用的 IEEE-754 格式,for (double x = 1.03; x <= 11.03; x += 1)将在x约为 10.03 而不是 11.03 时结束。它将递增到11.03000000 000501,01198828125,但11.03987654341 @ 98765432715988159999999881599999998815999999885999999988599999998859999998759999875,4876599999998859999999885913781590999999998875,so,so @ 987654396815909832715988599999998815999999988599999875,所以x <= 11.03评估为false。 span> -
使用linspace 风格的显式元素计数(并且没有默认计数,与 MATLAB 或 numpy linspace 不同)比从步长值开始并推导元素数量要安全得多从那里。面向计数而不是面向步长的方法消除了意外包含或排除端点的问题。
标签: c++ c++ templates floating-point iterator c++17