在近距离范围内循环

在近距离范围内循环

本文介绍了在近距离范围内循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您将如何解决此代码?

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 be numeric_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, since std::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, and omega<T> implicitly converts to T, 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, but omega<int>(INT_MAX) < endof(INT_MAX) is false.

      这篇关于在近距离范围内循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 15:18