首页 文章

C 11中是否有一个范围类用于基于范围的循环?

提问于
浏览
95

我发现自己刚刚写了这篇文章:

template <long int T_begin, long int T_end>
class range_class {
 public:
   class iterator {
      friend class range_class;
    public:
      long int operator *() const { return i_; }
      const iterator &operator ++() { ++i_; return *this; }
      iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }

      bool operator ==(const iterator &other) const { return i_ == other.i_; }
      bool operator !=(const iterator &other) const { return i_ != other.i_; }

    protected:
      iterator(long int start) : i_ (start) { }

    private:
      unsigned long i_;
   };

   iterator begin() const { return iterator(T_begin); }
   iterator end() const { return iterator(T_end); }
};

template <long int T_begin, long int T_end>
const range_class<T_begin, T_end>
range()
{
   return range_class<T_begin, T_end>();
}

这允许我写这样的东西:

for (auto i: range<0, 10>()) {
    // stuff with i
}

现在,我知道我写的可能不是最好的代码 . 也许有一种方法可以使它更灵活和有用 . 但在我看来,像这样的东西应该成为标准的一部分 .

它也是吗?是否在一系列整数上为迭代器添加了某种新库,或者可能是通用范围的计算标量值?

8 回答

  • 12

    C标准库没有一个,但Boost.Range has boost::counting_range,当然有资格 . 您也可以使用boost::irange,它在范围上更有针对性 .

    C 20的范围库允许您通过 view::iota(start, end) 执行此操作 .

  • 1

    据我所知,C 11中没有这样的课程 .

    无论如何,我试图改进你的实现 . 我把它设为非模板,因为我认为制作模板没有任何优势 . 相反,它有一个主要缺点:您无法在运行时创建范围,因为您需要在编译时知道模板参数 .

    //your version
    auto x = range<m,n>(); //m and n must be known at compile time
    
    //my version
    auto x = range(m,n);  //m and n may be known at runtime as well!
    

    这是代码:

    class range {
     public:
       class iterator {
          friend class range;
        public:
          long int operator *() const { return i_; }
          const iterator &operator ++() { ++i_; return *this; }
          iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }
    
          bool operator ==(const iterator &other) const { return i_ == other.i_; }
          bool operator !=(const iterator &other) const { return i_ != other.i_; }
    
        protected:
          iterator(long int start) : i_ (start) { }
    
        private:
          unsigned long i_;
       };
    
       iterator begin() const { return begin_; }
       iterator end() const { return end_; }
       range(long int  begin, long int end) : begin_(begin), end_(end) {}
    private:
       iterator begin_;
       iterator end_;
    };
    

    测试代码:

    int main() {
          int m, n;
          std::istringstream in("10 20");
          if ( in >> m >> n ) //using in, because std::cin cannot be used at coliru.
          {
            if ( m > n ) std::swap(m,n); 
            for (auto i : range(m,n)) 
            {
                 std::cout << i << " ";
            }
          }
          else 
            std::cout <<"invalid input";
    }
    

    输出:

    10 11 12 13 14 15 16 17 18 19

    Onine demo .

  • 2

    为了完全相同的目的,我编写了一个名为 range 的库,除了它是一个运行时范围,我的案例中的想法来自Python . 我认为是一个编译时版本,但在我看来,获得编译时版本并没有什么好处 . 您可以在bitbucket上找到该库,它位于Boost License: Range 下 . 它是一个单头库,与C 03兼容,在C 11中具有基于范围的for循环的魅力 .

    Features

    • 一个真正的随机访问容器,包含所有的铃声和口哨声!

    • 范围可以按字典顺序进行比较 .

    • 两个函数 exist (返回bool)和 find (返回迭代器)以检查是否存在数字 .

    • 使用CATCH对库进行单元测试 .

    • 基本用法示例,使用标准容器,使用标准算法并使用基于范围的for循环 .

    Here is a one-minute introduction . 最后,我欢迎任何有关这个小型图书馆的建议 .

  • 4

    我发现 boost::irange 比规范整数循环要慢得多 . 所以我使用预处理器宏来解决以下更简单的解决方案:

    #define RANGE(a, b) unsigned a=0; a<b; a++
    

    然后你可以像这样循环:

    for(RANGE(i, n)) {
        // code here
    }
    

    该范围自动从零开始 . 它可以很容易地扩展到从给定数字开始 .

  • -2

    这是一个更简单的形式,对我来说很好用 . 我的方法有风险吗?

    r_iterator 是一种尽可能像 long int 一样的行为 . 因此,许多运算符如 ==++ ,只是传递给 long int . 我'expose'通过 operator long intoperator long int & 转换的底层long int .

    #include <iostream>
    using namespace std;
    
    struct r_iterator {
            long int value;
            r_iterator(long int _v) : value(_v) {}
            operator long int () const { return value; }
            operator long int& ()      { return value; }
            long int operator* () const { return value; }
    };
    template <long int _begin, long int _end>
    struct range {
            static r_iterator begin() {return _begin;}
            static r_iterator end  () {return _end;}
    };
    int main() {
            for(auto i: range<0,10>()) { cout << i << endl; }
            return 0;
    }
    

    Edit: - 我们可以使用 range static而不是const的方法 . )

  • 45

    这可能有点晚了,但我刚看到这个问题,我现在已经使用这个课了一段时间了:

    #include <iostream>
    #include <utility>
    #include <stdexcept>
    
    template<typename T, bool reverse = false> struct Range final {
        struct Iterator final{
            T value;
            Iterator(const T & v) : value(v) {}
            const Iterator & operator++() { reverse ? --value : ++value; return *this; }
            bool operator!=(const Iterator & o) { return o.value != value; }
            T operator*() const { return value; }
        };
        T begin_, end_;
        Range(const T & b, const T & e)  : begin_(b), end_(e) {
            if(b > e) throw std::out_of_range("begin > end");
        }
    
        Iterator begin() const { return reverse ? end_ -1 : begin_; }
        Iterator end() const { return reverse ? begin_ - 1: end_; }
    
        Range() = delete;
        Range(const Range &) = delete;
    };
    
    using UIntRange = Range<unsigned, false>;
    using RUIntRange = Range<unsigned, true>;
    

    用法:

    int main() {
        std::cout << "Reverse : ";
        for(auto i : RUIntRange(0, 10)) std::cout << i << ' ';
        std::cout << std::endl << "Normal : ";
        for(auto i : UIntRange(0u, 10u)) std::cout << i << ' ';
        std::cout << std::endl;
    }
    
  • 0

    你试过用吗?

    template <class InputIterator, class Function>
       Function for_each (InputIterator first, InputIterator last, Function f);
    

    大部分时间都符合要求 .

    例如 .

    template<class T> void printInt(T i) {cout<<i<<endl;}
    void test()
    {
     int arr[] = {1,5,7};
     vector v(arr,arr+3);
    
     for_each(v.begin(),v.end(),printInt);
    
    }
    

    请注意,printInt可以用C 0x中的lambda替换OFC . 此用法的另一个小变化可能是(严格来说,对于random_iterator)

    for_each(v.begin()+5,v.begin()+10,printInt);
    

    对于Fwd只有迭代器

    for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);
    
  • 55

    您可以使用std :: iota()在C 11中轻松生成递增序列:

    #include <iostream>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    
    template<typename T>
    std::vector<T> range(T start, T end)
    {
      std::vector<T> r(end+1-start, T(0));
      std::iota(r.begin(), r.end(), T(start));//increasing sequence
      return r;
    }
    
    int main(int argc, const char * argv[])
    {
      for(auto i:range<int>(-3,5))
        std::cout<<i<<std::endl;
    
      return 0;
    }
    

相关问题