Reputation: 8099
I'm using Visual Studio 2012 so C++11 is mostly OK... boost is also fine, but I would prefer to avoid other libreries, at least not widley used ones.
I want to create a forward only iterator that returns an infinite sequence, in the most elegant way possible. For example a sequence of all the natural numbers.
Basically I want the C++ equivilent of this f# code:
let nums =
seq { while true do
yield 1
yield 2
}
the above code basically creates an enumerator that returns [1;2;1;2...]
I know I could do this by writing a class, but there's got to be a shorter way with all the new lambdas and all...
Upvotes: 7
Views: 4437
Reputation: 7663
The simpler thing, if you can depend on boost is to write something like this:
int i = 0;
auto gen = boost::make_generator_iterator([=]() mutable { return i++; });
C++14 version:
auto gen = boost::make_generator_iterator([i=0]() mutable { return i++;});
Documentation is here.
P.S.: I'm not sure if it will work without result_type
member, which C++03 functor would need.
Upvotes: 5
Reputation: 2724
Here is C++14 index_sequence comes helping:
#include <iostream>
#include <vector>
namespace std
{
template< int ...i> struct index_sequence{};
template< int N, int ...i>
struct make_seq_impl : make_seq_impl< N-1, N-1,i...> {};
template< int ...i>
struct make_seq_impl<0,i...>{ typedef index_sequence<i...> type; };
template< int N >
using make_index_sequence = typename make_seq_impl<N>::type;
} // namespace std
typedef std::vector<int> integer_list;
template< typename F, int ...i >
integer_list make_periodic_list_impl(F f, std::index_sequence<i...> )
{
// { 1 2 1 2 1 2... }
return { f(i) ... };
}
template< int N , typename F>
integer_list make_periodic_list(F f)
{
return make_periodic_list_impl(f, std::make_index_sequence<N>{} );
}
int main()
{
std::vector<int> v = make_periodic_list<20>([](int i){return 1 + (i&1);});
for( auto e : v ) std::cout << e << ' ';
}
Upvotes: 0
Reputation: 38173
Is this what you want:
#include <iostream>
#include <vector>
int main()
{
auto nums = []
{
static unsigned x = 2;
return ( x++ % 2 ) + 1;
};
std::vector< int > v{ nums(), nums(), nums(), nums(), nums() };
for( auto i : v )
{
std::cout << i;
}
return 0;
}
or I have misunderstood the question?
Upvotes: 5
Reputation: 361482
I've written a library called Pipeline using which you can write such things easily, as:
auto infinite_seq = generate(1, [](int i) { return (i % 2) + 1; });
Now infinite_seq
is a deferred-range which means it will generate the values and give you when you ask for it. If you ask for 10
values, it will generate exactly 10
values — this can be expressed as:
auto values = infinite_seq | take(10);
Or you can write this:
auto values = generate(1, [](int i) { return (i % 2) + 1; }) | take(10);
for(auto i : values)
//working with i
Have a look at the documentation of generate.
Upvotes: 3
Reputation: 25927
When you have a hammer in your hand, everything around looks like a nail. Lambdas and other C++11 features are sure cool, but you should choose valid tools for problems. In this case I see nothing simpler and more elegant than short class with overloaded operators:
class MyInfiniteIter
{
private:
unsigned int i;
public:
MyInfiniteIter()
{
i = 0;
}
int operator *() {
return i;
}
int operator++ () {
i++;
if (i == 10)
i = 0;
return i;
}
};
int main(int argc, char * argv[])
{
for (MyInfiniteIter i;; ++i)
{
printf("%d\n", *i);
}
}
Upvotes: 0
Reputation: 545608
Standard C++ has no real iterator generators which help you avoid writing the class manually. You can take a look at my range
library for such an iterator generator to get going. This code essentially allows you to write
for (auto i : range(1))
…
which generates the infinite sequence 1, 2, 3, …. Boost.Iterator contains tools for transforming one iterator output into another, related output. You could use that to repeatedly cycle over elements from a two-item container (containing the elements 1
and 2
, in your case).
Upvotes: 2