Как сделать бесконечную последовательность в C++
Я использую Visual Studio 2012, поэтому C++11 в основном в порядке... boost также прекрасен, но я бы предпочел избегать других библиотек, по крайней мере, не используемых уидли.
Я хочу создать итератор только вперед, который возвращает бесконечную последовательность самым элегантным способом. Например, последовательность всех натуральных чисел.
в основном я хочу c++ equivilent этого кода f#:
let nums =
seq { while true do
yield 1
yield 2
}
приведенный выше код в основном создает перечислитель, который возвращает [1;2;1;2...]
Я знаю, что мог бы сделать это, написав класс, но должен быть более короткий путь со всеми новыми лямбдами и всем остальным...
6 ответов
проще, если вы можете зависеть от boost, написать что-то вроде этого:
int i = 0;
auto gen = boost::make_generator_iterator([=]() { return i++; });
В C++14 версия:
auto gen = boost::make_generator_iterator([i=0]() { return i++;});
документация здесь.
П. С.: Я не уверен, если он будет работать без result_type
член, который понадобится функтору C++03.
это то, что вы хотите:
#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;
}
или я неправильно понял вопрос?
Я написал библиотеку под названием трубопровод используя который вы можете написать такие вещи легко, как:
auto infinite_seq = generate(1, [](int i) { return (i % 2) + 1; });
теперь infinite_seq
- это отсроченный-диапазон что означает, что это будет создать значения и дать вам , когда вы просите об этом. Если вы попросите 10
значения, он будет генерировать именно 10
значения - это может быть выражено как:
auto values = infinite_seq | take(10);
или вы можете написать это:
auto values = generate(1, [](int i) { return (i % 2) + 1; }) | take(10);
for(auto i : values)
//working with i
посмотреть документация создать.
Standard C++ не имеет реальных генераторов итераторов, которые помогут вам избежать написания класса вручную. Вы можете взглянуть на мой range
библиотека для такого генератора итератора, чтобы начать работу. Этот код по существу позволяет писать
for (auto i : range(1))
…
который генерирует бесконечную последовательность 1, 2, 3, .... импульс.Итератор содержит инструменты для преобразования одного вывода итератора в другой, связанный вывод. Вы можете использовать это для повторного цикла элементов из двухэлементный контейнер (содержащий элементы 1
и 2
в вашем случае).
когда у вас в руке молоток, все вокруг выглядит как гвоздь. Lambdas и другие функции C++11, конечно, классные, но вы должны выбрать правильные инструменты для проблем. В этом случае я не вижу ничего проще и элегантнее, чем короткие класс с перегруженными операторами:
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);
}
}
вот C++14 index_sequence приходит помогать:
#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 << ' ';
}