簡體   English   中英

C++11 中是否有范圍類用於基於范圍的 for 循環?

[英]Is there a range class in C++11 for use with range based for loops?

我發現自己剛剛在寫這個:

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
}

現在,我知道我寫的可能不是最好的代碼。 也許有一種方法可以使它更靈活和有用。 但在我看來,這樣的事情應該成為標准的一部分。

是嗎? 是否為整數范圍內的迭代器添加了某種新庫,或者可能是計算標量值的通用范圍?

C++ 標准庫沒有,但Boost.Range 有 boost::counting_range ,這當然有資格。 您還可以使用boost::irange ,它的范圍更集中一些。

C++20 的范圍庫將允許您通過view::iota(start, end)執行此操作。

據我所知,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

在線演示

我為完全相同的目的編寫了一個名為range的庫,只是它是一個運行時范圍,在我的例子中這個想法來自 Python。 我考慮過編譯時版本,但在我看來,獲得編譯時版本並沒有真正的優勢。 您可以在 bitbucket 上找到該庫,它位於 Boost License: Range 下 它是一個單頭庫,與 C++03 兼容,並且在 C++11 中使用基於范圍的 for 循環就像魅力一樣工作:)

特點

  • 一個真正的隨機訪問容器,具有所有花里胡哨的功能!

  • 范圍可以按字典順序進行比較。

  • exist兩個函數(返回 bool)和find (返回迭代器)來檢查數字是否存在。

  • 該庫使用CATCH進行單元測試。

  • 基本用法示例、使用標准容器、使用標准算法以及使用基於范圍的 for 循環。

這是一個一分鍾的介紹 最后,我歡迎任何關於這個小圖書館的建議。

我發現boost::irange比規范整數循環慢得多。 因此,我使用預處理器宏確定了以下更簡單的解決方案:

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

然后你可以像這樣循環:

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

該范圍自動從零開始。 它可以很容易地擴展到從給定的數字開始。

這是一個更簡單的形式,對我來說很好用。 我的方法有什么風險嗎?

r_iterator是一種行為盡可能像long int 因此,許多運算符,例如==++ ,只是傳遞給long int 我通過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;
}

編輯: - 我們可以使range的方法靜態而不是 const。)

這可能有點晚了,但我剛看到這個問題,我已經使用這個類有一段時間了:

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

你有沒有試過使用

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

}

請注意,在 C++0x 中,printInt 可以被 OFC 替換為 lambda。 這種用法的另一個小變化可能是(嚴格用於 random_iterator)

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

對於 Fwd only 迭代器

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

您可以使用 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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM