4

您将如何修复此代码?

template <typename T> void closed_range(T begin, T end)
{
    for (T i = begin; i <= end; ++i) {
        // do something
    }
}
  • T 被限制为整数类型,可以是更广泛的此类类型,并且可以是有符号或无符号的

  • beginnumeric_limits<T>::min()

  • end可以numeric_limits<T>::max()(在这种情况下++i会在上面的代码中溢出)

我有好几种方法,但没有一个是我真正喜欢的。

4

5 回答 5

6

也许,

template <typename T> void closed_range(T begin, const T end)
    if (begin <= end) {
        do {
            // do something
        } while (begin != end && (++begin, true));
    }
}

诅咒,我的第一次尝试是错误的,上面的修复并不像我希望的那样漂亮。怎么样:

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));
    }
}

std::advance即使 T 不是整数类型也没有歧义,因为std::advance它需要 2 个参数。因此,如果出于某种原因您想要一个封闭的范围,该模板也可以与例如随机访问迭代器一起使用。

或者一些集合论怎么样?显然,如果您只在一个封闭范围内编写一个循环,这将是巨大的矫枉过正,但如果这是您想要做的很多事情,那么它会使循环代码正确。不确定效率:在一个非常紧凑的循环中,您可能需要确保调用endof被提升:

#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 为真,则在转换中抛出异常;或者只是不要担心它,因为你不能不小心将结果转换回欧米茄,因为构造函数是显式的。但是例如,omega<int>(2) < endof(2)是真的,但是omega<int>(INT_MAX) < endof(INT_MAX)是假的。

于 2010-03-16T19:35:47.947 回答
5

我的看法:

// Make sure we have at least one iteration
if (begin <= end)
{
    for (T i = begin; ; ++i)
    {
        // do something

        // Check at the end *before* incrementing so this won't
        // be affected by overflow
        if (i == end)
            break;
    }
}
于 2010-03-16T19:25:57.910 回答
3

这有效并且相当清楚:

T i = begin;
do {
   ...
}
while (i++ < end);

如果你想捕捉特殊情况,begin >= end你需要if在史蒂夫杰索普的解决方案中添加另一个类似的东西。

于 2010-03-16T19:36:58.417 回答
3
template <typename T, typename F>
void closed_range(T begin, T end, F functionToPerform) 
{
    for (T i = begin; i != end; ++i) { 
        functionToPerform(i);
    }
    functionToPerform(end);
} 
于 2010-03-16T20:23:35.343 回答
0

编辑:重新设计以更紧密地匹配 OP。

#include <iostream>
using namespace std;

template<typename T> void closed_range(T begin, T end)
{
    for( bool cont = (begin <= end); cont; )
    {
        // do something
        cout << begin << ", ";
        if( begin == end )
            cont = false;
        else
            ++begin;
    }

    // test - this should return the last element
    cout << " --  " << begin;
}
int main()
{
    closed_range(10, 20);
    return 0;
}

输出是:

10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -- 20

于 2010-03-16T20:11:25.253 回答