Stack Overflow на русском Asked by dIm0n on February 6, 2021
Как в C++ написать генератор, как в питоне?
Например, для чисел Фибоначчи генератор можно написать и использовать так:
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
g = fib()
print(next(g), next(g), next(g))
for f in fib():
print(f)
if (f > 1000):
break
Как сделать то же в C++?
Ну, раз пошла такая пьянка...
Я бы делал в стиле итератора:
class Fib
{
public:
Fib():f0(0),f1(1){}
Fib& operator ++(int) { unsigned long long f = f0+f1; f0 = f1; f1 = f; return *this; }
unsigned long long operator*() { return f0; }
private:
unsigned long long f0, f1;
};
int main(int argc, const char * argv[])
{
for(Fib f; *f < 1000000000000ull;)
cout << *f++ << endl;
}
Answered by Harry on February 6, 2021
Пускай лучше считает компилятор:
//некоторое число Фибоначчи
template<size_t n>
struct Fib {
enum { res = Fib<n - 1>::res + Fib<n - 2>::res };
};
template<>
struct Fib<0> {
enum { res = 0 };
};
template<>
struct Fib<1> {
enum { res = 1 };
};
//шаблон, хранивший массив
template <size_t n, size_t...args>
struct Fib_аrr {
static constexpr auto& array =
Fib_arr<n - 1, Fib<n>::res, args...>::array;
};
template <size_t...args>
struct Fib_arr<0, args...> {
static constexpr int array[] = { 0, args... };
};
//теперь массив чисел Фибоначчи до элемента,
// номер которого задан в параметре шаблона
template <size_t n>
struct Fib_array {
static constexpr auto& array =
Fib_arr<n>::array;
};
//а генератор выдаст случайный элемент из массива
template <size_t s >
struct Fib_gen {
int operator ()() { return Fib_array<s>::array[(rand() % s)]; }
};
Программа просто выводит элемент массива
int main() {
//генерировать 20 случайных от 1 до 13 элемента чисел Фибоначчи
Fib_gen<13> g;
for (int i = 1; i < 20; ++i)
cout << g() << ' ';
//или просто вывести 0... 20 элементы
for (int i = 0; i < 20; ++i)
cout << Fib_array<20>::array[i] << ' ';
return 0;
}
Answered by AR Hovsepyan on February 6, 2021
Почти так же:
#include <coroutine>
#include <tuple>
#include <iostream>
generator fib() {
int a = 0, b = 1;
while (true) {
co_yield a;
std::tie(a, b) = std::make_tuple(b, a + b);
}
}
int main() {
auto gen_1 = fib();
std::cout << gen_1.current_value(); gen_1.move_next();
std::cout << gen_1.current_value(); gen_1.move_next();
std::cout << gen_1.current_value() << 'n';
auto gen = fib();
for (auto cur = gen.current_value();; gen.move_next(), cur = gen.current_value()) {
std::cout << cur << 'n';
if (cur > 1000)
break;
}
}
Чтобы было совсем похоже, надо ещё функцию next
сделать, чтобы продвигала + возвращала значение генератора, и добавить итераторы для генератора, чтобы использовать в range for цикле вместе с break
.
Компилить с -std=c++2a -fcoroutines
.
Если в стандартной библиотеке ещё не реализован генератор, то вот:
#include <coroutine>
#include <exception>
struct generator {
struct promise_type {
int current_value;
static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }
auto get_return_object() { return generator{handle::from_promise(*this)}; }
auto initial_suspend() { return std::suspend_always{}; }
auto final_suspend() { return std::suspend_always{}; }
void unhandled_exception() { std::terminate(); }
void return_void() {}
auto yield_value(int value) {
current_value = value;
return std::suspend_always{};
}
};
using handle = std::coroutine_handle<promise_type>;
bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
int current_value() { return coro.promise().current_value; }
generator(generator const&) = delete;
generator(generator&& rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
~generator() { if (coro) coro.destroy(); }
private:
generator(handle h) : coro(h) {}
handle coro;
};
Answered by dIm0n on February 6, 2021
думаю можно через класс, просто хранить состояние в обьекте, и каждый раз получать следующее значение через next
#include <iostream>
class Fibonacci
{
private:
int a, b, c;
public:
Fibonacci() :a(0), b(1), c(0) {}
friend int next(Fibonacci& fib)
{
fib.c = fib.a + fib.b;
fib.a = fib.b;
fib.b = fib.c;
return fib.c;
}
};
int main()
{
Fibonacci fib;
for (int i = 0;i < 15;++i) {
std::cout << next(fib) << 'n';
}
return 0;
}
еще можно добавить итераторы чтобы можно было итерироваться в range-based for
Answered by Ildar on February 6, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP