6

If I got that right I can use this to iterate over a fixed range:

for(int i: {1, 2, 3, 4, 5})
    do_sth(i);

And this is the same thing:

vector<int> v{1, 2, 3, 4, 5};
for(int i: v)
    do_sth(i);

But what if I want to iterate over the range of 1, ..., 100 and already know that at compile time? What is the most beautiful way to do that? What the most efficient? What the shortest?

Edit: of course I could write a regular for loop, but the actual use case would involve more complicated content than ints.

I just oversimplified the example a bit.

black_puppydog
  • 950
  • 13
  • 21
  • Or you could use a macro, but they're evil, so yeah. – Vittorio Romeo Sep 18 '13 at 12:41
  • Actually, you could generate the range at compile time using template recursion, but that only works for POD types, and you'd be limited by the maximum template recursion the compiler allows – Charles Salvia Sep 18 '13 at 12:42
  • @black_puppydog Your edit changes the question more than you might think. What is the real situation? – BoBTFish Sep 18 '13 at 12:52
  • @BoBTFish I actually wanted to iterate over a predefined list/vector of STL objects, but I think I'll just write a simple iterator that does the job since actually it fits better. I guess I was hoping a little for some automagic but I think with C++ I won't get that :D sorry for the confusion. – black_puppydog Sep 18 '13 at 12:58
  • 1
    Please look at the solution of Khurshid Normuradov at http://stackoverflow.com/questions/18483706/range-based-loop-c11-for-rangel-r/18484480#18484480 –  Sep 18 '13 at 13:09

6 Answers6

16
for( int i = 1; i <= 100; ++i )
{
    do_sth( i );
}

?

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
  • 3
    Simple is beautiful. ;-) – Paul R Sep 18 '13 at 12:48
  • 1
    Andrew Koenig has much to say on the joys of asymmetric bounds! [Part 1](http://www.drdobbs.com/cpp/asymmetric-bounds-part-1-what-are-they/240001666). But yes, just do this. – BoBTFish Sep 18 '13 at 12:50
  • 2
    @black_puppydog - this totally changes the situation. That just became absolutely different question. – Kiril Kirov Sep 18 '13 at 12:55
  • 3
    +1 - I prefer the more verbose readability of this simple code over complicated short constructs that are not widely known (yet). This is readable by even the most novice C++ programmer. – Tobias Langner Sep 18 '13 at 12:57
  • @KirilKirov agreed, things change pretty quickly here, experimenting with the code for the next homework assignment and different algorithms. on a small meta: how to proceed? close question? – black_puppydog Sep 18 '13 at 13:02
  • @black_puppydog - no, no, leave it like this, as you have found your answer here. – Kiril Kirov Sep 18 '13 at 13:03
  • Original answer mentions that this could be any other types besides int. `for` loop is good for numbers only. – kworr Sep 28 '13 at 09:20
  • @kworr - first of all, this doesn't make my answer incorrect to deserve a down-vote. And second - if you see more carefully, you'll see, that the note about the `for` is an edit (which was done after I posted my answer). – Kiril Kirov Sep 28 '13 at 10:25
4

If you really want it in a container, you can fill a container using the std::iota function. Otherwise use a normal for loop.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
4

You can "easily" write a for-range-compatible class that represents an integer range. You just have to write the iterators for it.

Or you can use Boost.Range's counting_range, which is exactly that.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
1

Use a range-for with a function template:

namespace detail
{
    template <int... Is>
    struct index { };

    template <int N, int... Is>
    struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };

    template <int... Is>
    struct gen_seq<0, Is...> : index<Is...> { };
}

template <int... Is>
std::array<int, sizeof...(Is)> range(detail::index<Is...>)
{
    return {{ Is... }};
}

template <int N>
std::array<int, N> range()
{
    return range(detail::gen_seq<N>{});
}

Example:

for (auto i : range<5>())
{
    do_sth(i);
}
David G
  • 94,763
  • 41
  • 167
  • 253
1

Example of an iterator-based technique, as Sebastian Redl mentioned:

class range {
public:
    struct rangeIt{
        rangeIt(int v) : _v(v){}
        int operator*()const{return _v;}
        void operator++(){_v++;}
        bool operator!=(const rangeIt & other)const{ return _v != other._v;}
    private:
        int _v;
    };
    range(int a, int b):_a(a),_b(b){}
    rangeIt begin() const { return rangeIt(_a); }
    rangeIt end() const { return rangeIt(_b); }
private:
    int _a, _b;
};

Then it can be used like this:

for(int i : range(0, 100)) {
  printf("%d\n", i);
}
hasvn
  • 1,054
  • 1
  • 11
  • 15
0
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> operator"" _r(const char* text, const size_t)
{
    string txt(text);

    auto delim  = txt.find('-');
    auto first  = txt.substr( 0, delim);
    auto second = txt.substr(delim + 1);

    int lower = stoi(first);
    int upper = stoi(second);

    vector<int> rval(upper - lower);

    generate(rval.begin(), rval.end(), [&]{ return lower++; } );

    return rval;
}

int main() 
{
    for(auto& el : "10-100"_r)
        cout<<el<<"\n";
}

Big runtime overhead, error prone ( mainly my implementation )... just the way I like it !

But it does solve the problem and even has a not-that-ugly syntax :)

user1233963
  • 1,450
  • 15
  • 41