问题描述
您将如何解决此代码?
template <typename T> void closed_range(T begin, T end)
{
for (T i = begin; i <= end; ++i) {
// do something
}
}
-
T被限制为整数类型,可以是此类类型中的更宽泛的类型,并且可以是有符号的或无符号的
T is constrained to be an integer type, can be the wider of such types and can be signed or unsigned
begin
可以是numeric_limits<T>::min()
end
可以是numeric_limits<T>::max()
(在这种情况下,++i
将在上面的代码中溢出)end
can benumeric_limits<T>::max()
(in which case++i
will overflow in the above code)我有几种方法,但我都不喜欢.
I've several ways, but none I really like.
推荐答案
也许
template <typename T> void closed_range(T begin, const T end) if (begin <= end) { do { // do something } while (begin != end && (++begin, true)); } }
顺便说一句,我的第一次尝试是错误的,并且上面的修复方法没有我希望的那么好.怎么样:
Curses, my first attempt was wrong, and the fix above isn't as pretty as I'd hoped. How about:
template <typename T> bool advance(T &value) { ++value; return true; } template <typename T> void closed_range(T first, const T last) if (first <= last) { do { // do something } while (first != last && advance(first)); } }
即使T不是整数类型,
std::advance
也没有歧义,因为std::advance
具有2个参数.因此,如果您出于某种原因想要一个封闭范围的模板,该模板还可以与例如随机访问迭代器一起使用.There's no ambiguity with
std::advance
even if T isn't an integer type, sincestd::advance
takes 2 parameters. So the template would also work with for instance a random-access iterator, if for some reason you wanted a closed range of those.或者说一些集合论呢?显然,如果只在一个封闭范围内编写一个循环,则这是巨大的杀伤力,但是如果您想做很多事情,那么循环代码就正确了.不确定效率:在一个非常紧密的循环中,您可能希望确保悬挂
endof
的调用:Or how about a bit of set theory? Obviously this is massive overkill if you're only writing one loop over a closed range, but if it's something that you want to do a lot, then it makes the loop code about right. Not sure about efficiency: in a really tight loop you might want make sure the call to
endof
is hoisted:#include <limits> #include <iostream> template <typename T> struct omega { T val; bool isInfinite; operator T() { return val; } explicit omega(const T &v) : val(v), isInfinite(false) { } omega &operator++() { (val == std::numeric_limits<T>::max()) ? isInfinite = true : ++val; return *this; } }; template <typename T> bool operator==(const omega<T> &lhs, const omega<T> &rhs) { if (lhs.isInfinite) return rhs.isInfinite; return (!rhs.isInfinite) && lhs.val == rhs.val; } template <typename T> bool operator!=(const omega<T> &lhs, const omega<T> &rhs) { return !(lhs == rhs); } template <typename T> omega<T> endof(T val) { omega<T> e(val); return ++e; } template <typename T> void closed_range(T first, T last) { for (omega<T> i(first); i != endof(last); ++i) { // do something std::cout << i << "\n"; } } int main() { closed_range((short)32765, std::numeric_limits<short>::max()); closed_range((unsigned short)65533, std::numeric_limits<unsigned short>::max()); closed_range(1, 0); }
输出:
32765 32766 32767 65533 65534 65535
在
omega<T>
对象上使用其他运算符时要格外小心.我只为演示实现了绝对最小值,并且omega<T>
隐式转换为T
,因此您会发现您可以编写可能抛弃omega对象无限"的表达式.您可以通过声明(不必定义)一整套算术运算符来解决此问题.或在isInfinite为true的情况下在转换中引发异常;或只是不必担心它,因为构造函数是显式的,因此您不能将结果意外地转换回omega.但是例如,omega<int>(2) < endof(2)
为true,而omega<int>(INT_MAX) < endof(INT_MAX)
为false.Be a bit careful using other operators on
omega<T>
objects. I've only implemented the absolute minimum for the demonstration, andomega<T>
implicitly converts toT
, so you'll find that you can write expressions which potentially throw away the "infiniteness" of omega objects. You could fix that by declaring (not necessarily defining) a full set of arithmetic operators; or by throwing an exception in the conversion if isInfinite is true; or just don't worry about it on grounds that you can't accidentally convert the result back to an omega, because the constructor is explicit. But for example,omega<int>(2) < endof(2)
is true, butomega<int>(INT_MAX) < endof(INT_MAX)
is false.这篇关于在近距离范围内循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!