2013-11-28 6 views
5

Я использую Visual Studio 2012, поэтому C++ 11 в основном ОК ... Ускорение тоже прекрасное, но я бы предпочел избегать других libreries, по крайней мере, ,Как сделать бесконечную последовательность в C++

Я хочу создать только первый итератор, который возвращает бесконечную последовательность, самым элегантным способом. Например, последовательность всех натуральных чисел.

В основном я хочу C++ equivilent этого F # код:

let nums = 
    seq { while true do 
      yield 1 
      yield 2 
     } 

приведенный выше код в основном создает перечислитель, который возвращает [1, 2, 1, 2 ...]

Я знаю, что я могли бы сделать это, написав класс, но там должен быть короткий путь со всеми новыми лямбды и все ...

+6

Я полагаю, что если вы * действительно * не хотите, чтобы написать класс, то вы можете использовать 'повышение :: transform_iterator' применяется к' импульса: : counting_iterator '. Lambdas предоставляет анонимные типы функторов, они не предоставляют анонимных типов итераторов. Поэтому сами по себе они не могут использоваться для определения итератора. –

+1

[Boost Coroutine] (http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/index.html) позволяет писать код в стиле вашей выборки f #. – ComicSansMS

+1

Просто предупреждение: C++ не доходит до бесконечности. Это по своей природе нетерпеливо и строго оценивается, а это значит, что вам нужно уйти с пути, чтобы он работал хорошо. – Xeo

ответ

3

Чем проще вещь, если вы можете зависеть от усиления, чтобы написать что-то вроде этого:

int i = 0; 
auto gen = boost::make_generator_iterator([=]() { return i++; }); 

C + +14 версия:

auto gen = boost::make_generator_iterator([i=0]() { return i++;}); 

Документация: here.

P.S .: Я не уверен, что он будет работать без члена result_type, которому нужен функтор C++ 03.

+0

+1. Мне очень нравится повышение: -P –

+0

Иногда это помогает :) –

+1

Это замечательно, но у меня болит голова ... –

4

Является ли это то, что вы хотите:

#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; 
} 

или я неправильно понял вопрос?

+0

Это общее направление, но я хочу что-то, что представляет собой коллекцию, которую я мог бы передать STL. –

+0

@AK_: существует несколько стандартных алгоритмов, которые имеют смысл при передаче бесконечной повторяющейся последовательности. Что конкретно вы планируете использовать? –

+0

@AK_ - что вы подразумеваете под «придать STL»? –

2

В стандартном C++ нет настоящих генераторов итераторов, которые помогут избежать записи класса вручную. Вы можете взглянуть на мой range library для такого итерационного генератора. Этот код по существу позволяет вам написать

for (auto i : range(1)) 
    … 

, который генерирует бесконечную последовательность 1, 2, 3, .... Boost.Iterator содержит инструменты для преобразования одного выхода итератора в другой, связанный с ним вывод. Вы можете использовать это для многократного перебора элементов из контейнера из двух предметов (содержащих элементы 1 и 2, в вашем случае).

+1

Я только кратко просмотрел ваш код библиотеки, но, во-первых, не нужно ли «range (1U)» избегать переполнения UB? Во-вторых, ваш класс 'infin_range_proxy' поддерживает' boost :: adapters :: transform (range (0U), [] (unsigned i) {return (i% 2) + 1;}) '? Я думаю, что это происходит потому, что у него есть 'begin()' и 'end()', но если ему нужно что-то еще, тогда он должен добавить следующее :-) –

+0

+1. Ваше librery выглядит хорошо, но я не буду использовать его. У меня нет информации, чтобы просмотреть ее ... –

+0

@SteveJessop Я просто не позволял ей переполняться ... ;-) Обычно вы используете бесконечные последовательности в начале, а затем усекаете их позже. Во-вторых, я фактически не смотрел на совместимость с Boost.Iterator вообще из-за нехватки времени. Я бы хотел сделать это в какой-то момент. –

3

Я написал библиотеку под названием Pipeline с помощью которого вы можете писать такие вещи легко, как:

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 

Посмотрите документацию generate.

+0

1. Опять же, я предпочитаю избегать библиотек, которые не принимаются крупным сообществом. 2. Я не сомневаюсь в ваших знаниях на C++, но вы делаете много утверждений о LINQ, которые НЕВОЗМОЖНО. –

+0

@AK_: Нет проблем. Я не утверждаю, что это тоже идеально. Надеюсь, вы получите * идеальное решение. Что касается LINQ, это просто вдохновение, моя библиотека НЕ ​​такая же и идентична LINQ. – Nawaz

+0

... Я хотел бы знать * почему * вы считаете, что LINQ «* НЕВОЗМОЖНО?»? – Nawaz

0

Когда у вас есть молот в руке, все вокруг выглядит как гвоздь. 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); 
    } 
} 
+1

'Я знаю, что я мог бы сделать это, написав класс, но должен быть более короткий путь со всеми новыми лямбдами и всеми ...' –

+0

'Новые лямбды и все', кажется, не являются хорошим выбором здесь. Их чистое существование не оправдывает их использование нигде, и в этом конкретном случае - на мой взгляд - простой класс - это самое элегантное решение. – Spook

+1

Согласен (в общем), но OP по какой-то причине не хочет классов.Может быть, даже образовательная цель, не знаю. –

0

Вот 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 << ' '; 
} 
Смежные вопросы