C++11 中是否有范围类用于基于范围的 for 循环?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7185437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a range class in C++11 for use with range based for loops?
提问by Omnifarious
I found myself writing this just a bit ago:
我发现自己刚刚在写这个:
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>();
}
And this allows me to write things like this:
这让我可以写这样的东西:
for (auto i: range<0, 10>()) {
// stuff with i
}
Now, I know what I wrote is maybe not the best code. And maybe there's a way to make it more flexible and useful. But it seems to me like something like this should've been made part of the standard.
现在,我知道我写的可能不是最好的代码。也许有一种方法可以使它更灵活和有用。但在我看来,这样的事情应该成为标准的一部分。
So is it? Was some sort of new library added for iterators over a range of integers, or maybe a generic range of computed scalar values?
是吗?是否为整数范围内的迭代器添加了某种新库,或者可能是计算标量值的通用范围?
采纳答案by Nicol Bolas
The C++ standard library does not have one, but Boost.Range has boost::counting_range, which certainly qualifies. You could also use boost::irange, which is a bit more focused in scope.
C++ 标准库没有,但Boost.Range 有 boost::counting_range,这当然有资格。您还可以使用boost::irange,它的范围更集中一些。
C++20's range library will allow you to do this via view::iota(start, end)
.
C++20 的范围库将允许您通过view::iota(start, end)
.
回答by Nawaz
As far as I know, there is no such class in C++11.
据我所知,C++11 中没有这样的类。
Anyway, I tried to improve your implementation. I made it non-template, as I don't see any advantagein making it template. On the contrary, it has one major disadvantage : that you cannot create the range at runtime, as you need to know the template arguments at compile time itself.
无论如何,我试图改进您的实施。我做了非模板,因为我看不到任何优势在使其模板。相反,它有一个主要缺点:您无法在运行时创建范围,因为您需要在编译时知道模板参数本身。
//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!
Here is the code:
这是代码:
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_;
};
Test code:
测试代码:
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";
}
Output:
输出:
10 11 12 13 14 15 16 17 18 19
10 11 12 13 14 15 16 17 18 19
在线演示。
回答by AraK
I wrote a library called range
for exactly the same purpose except it is a run-time range, and the idea in my case came from Python. I considered a compile-time version, but in my humble opinion there is no real advantage to gain out the compile-time version. You can find the library on bitbucket, and it is under Boost License: Range. It is a one-header library, compatible with C++03 and works like charm with range-based for loops in C++11 :)
我写了一个range
完全相同目的的库,只是它是一个运行时范围,在我的例子中这个想法来自 Python。我考虑过编译时版本,但在我看来,获得编译时版本并没有真正的优势。您可以在 bitbucket 上找到该库,它位于 Boost License: Range 下。它是一个单头库,与 C++03 兼容,并且在 C++11 中使用基于范围的 for 循环就像魅力一样工作:)
Features:
特点:
A true random access container with all the bells and whistles!
Ranges can be compared lexicographically.
Two functions
exist
(returns bool), andfind
(returns iterator) to check the existence of a number.The library is unit-tested using CATCH.
Examples of basic usage, working with standard containers, working with standard algorithms and working with range based for loops.
一个真正的随机访问容器,具有所有花里胡哨的功能!
范围可以按字典顺序进行比较。
两个函数
exist
(返回 bool)和find
(返回迭代器)来检查数字是否存在。该库使用CATCH进行单元测试。
基本用法示例、使用标准容器、使用标准算法以及使用基于范围的 for 循环。
Here is a one-minute introduction. Finally, I welcome any suggestion about this tiny library.
这是一个一分钟的介绍。最后,我欢迎任何关于这个小图书馆的建议。
回答by user2664470
I found that boost::irange
was much slower than the canonical integer loop. So I settled on the following much simpler solution using a preprocessor macro:
我发现这boost::irange
比规范整数循环慢得多。因此,我使用预处理器宏确定了以下更简单的解决方案:
#define RANGE(a, b) unsigned a=0; a<b; a++
Then you can loop like this:
然后你可以像这样循环:
for(RANGE(i, n)) {
// code here
}
This range automatically starts from zero. It could be easily extended to start from a given number.
该范围自动从零开始。它可以很容易地扩展到从给定的数字开始。
回答by Aaron McDaid
Here is a simpler form which is working nicely for me. Are there any risks in my approach?
这是一个更简单的形式,对我来说很好用。我的方法有什么风险吗?
r_iterator
is a type which behaves, as much as possible, like a long int
. Therefore many operators such as ==
and ++
, simply pass through to the long int
. I 'expose' the underlying long int via the operator long int
and operator long int &
conversions.
r_iterator
是一种行为尽可能像 a 的类型long int
。因此,许多运算符,例如==
and ++
,只是简单地传递到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;
}
(Edit:- we can make the methods of range
static instead of const.)
(编辑:- 我们可以使方法range
静态而不是常量。)
回答by OneOfOne
This might be a little late but I just saw this question and I've been using this class for a while now :
这可能有点晚了,但我刚看到这个问题,我已经使用这个类有一段时间了:
#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>;
Usage :
用法 :
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;
}
回答by Ajeet Ganga
have you tried using
你有没有试过使用
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function f);
Most of the time fits the bill.
大多数时间都符合要求。
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);
}
Note that printInt can OFC be replaced with a lambda in C++0x. Also one more small variation of this usage could be (strictly for random_iterator)
请注意,在 C++0x 中,printInt 可以被 OFC 替换为 lambda。这种用法的另一个小变化可能是(严格用于 random_iterator)
for_each(v.begin()+5,v.begin()+10,printInt);
For Fwd only iterator
对于 Fwd only 迭代器
for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);
回答by blue scorpion
You can easily generate an increasing sequence in C++11 using std::iota():
您可以使用 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;
}