C ++ 11中是否有一个范围类,用于基于范围的循环?
我发现自己写了一些:
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 ++ 11中没有这样的类。
无论如何,我试图改善您的实施。 我使它成为非模板 ,因为我没有看到它使模板的 优势 。 相反,它有一个主要的缺点:你不能在运行时创build范围,因为你需要在编译时自己知道模板参数。
//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_; };
testing代码:
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上find这个库,它在Boost License: Range下 。 它是一个单头库,与C ++ 03兼容,并且像C ++ 11中基于范围循环一样工作。
特点 :
-
一个真正的随机存取容器与所有的花里胡哨!
-
范围可以按字典顺序进行比较。
-
exist
两个函数(返回bool),find
(返回迭代器)来检查数字的存在。 -
该库使用CATCH进行unit testing。
-
基本用法的示例,使用标准容器,使用标准algorithm和使用基于范围的循环。
这是一分钟的介绍 。 最后,我欢迎任何关于这个小图书馆的build议。
我发现boost::irange
比规范的整数循环慢得多。 所以我使用预处理器macros来解决以下更简单的解决scheme:
#define RANGE(a, b) unsigned a=0; a<b; a++
那么你可以这样循环:
for(RANGE(i, n)) { // code here }
该范围自动从零开始。 它可以很容易地扩展到从一个给定的数字开始。
这是一个更简单的forms,对我来说很好。 我的方法有没有风险?
r_iterator
是一个尽可能像long int
一样的行为。 因此,许多运算符(如==
和++
)只是传递给long int
。 我通过operator long int
和operator long int &
conversions来“暴露”底层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
静态,而不是常量的方法。
你有没有尝试过使用
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中的lambdareplaceOFC。 另外这个用法的另一个小的变化可能是(严格来说是random_iterator)
for_each(v.begin()+5,v.begin()+10,printInt);
仅用于Fwd迭代器
for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);
这可能有点晚了,但我刚刚看到这个问题,我一直在使用这个类有一段时间:
#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; }
你可以使用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; }