我发现自己刚刚写了这篇文章:
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
}
现在,我知道我写的可能不是最好的代码。也许有一种方法可以使它更灵活和有用。但在我看来,像这样的东西应该成为标准的一部分。
它也是吗?是否在一系列整数上为迭代器添加了某种新库,或者可能是通用范围的计算标量值?
答案 0 :(得分:55)
C ++标准库没有一个,但是Boost.Range has boost::counting_range,它当然有资格。您也可以使用boost::irange,这在范围上更有针对性。
C ++ 20的范围库允许您通过view::iota(start, end)
。
答案 1 :(得分:45)
据我所知,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
答案 2 :(得分:12)
我编写了一个名为range
的库,其目的完全相同,只是它是一个运行时范围,而我的案例中的想法来自Python。我认为是一个编译时版本,但在我看来,获得编译时版本并没有什么好处。您可以在bitbucket上找到该库,它位于Boost许可证下: Range 。它是一个单头库,与C ++ 03兼容,并且像C ++ 11中的基于范围的for循环一样工作:)
功能:
一个真正的随机访问容器,包含所有的铃声和口哨声!
范围可以按字典顺序进行比较。
两个函数exist
(返回
bool)和find
(返回迭代器)来检查数字是否存在。
使用CATCH对库进行单元测试。
基本的例子 使用,使用标准容器,使用标准 算法并使用基于范围的循环。
Here is a one-minute introduction。最后,我欢迎任何有关这个小型图书馆的建议。
答案 3 :(得分:4)
我发现boost::irange
比规范整数循环慢得多。所以我使用预处理器宏来解决以下更简单的解决方案:
#define RANGE(a, b) unsigned a=0; a<b; a++
然后你可以像这样循环:
for(RANGE(i, n)) {
// code here
}
此范围自动从零开始。它可以很容易地扩展到从给定数字开始。
答案 4 :(得分:2)
这是一个更简单的形式,对我来说很好用。我的方法有风险吗?
r_iterator
是一种尽可能像long int
一样行事的类型。因此,许多运营商(例如==
和++
)只会传递到long int
。我通过operator long int
和operator 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
的方法设为静态而不是常量。)
答案 5 :(得分:1)
这可能有点晚了,但我刚看到这个问题,我现在已经使用这个课了一段时间了:
#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;
}
答案 6 :(得分:0)
你尝试过使用
吗?template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function f);
大部分时间都符合要求。
E.g。
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);
答案 7 :(得分:-2)
使用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;
}