История изменений
Исправление Kroz, (текущая версия) :
Вобщем, я так понял, что это всё еще в экспериментальном состоянии. GCC экспериментально поддерживает в версии 10 (https://gcc.gnu.org/projects/cxx-status.html), clang с версии 9.0. Но я на clang не смог запустить, а десятку GCC вот сечас ставлю.
И там основная хитрость - написать генератор - который по идее должен быть в стандартной библиотеке, но пока это не так.
Пару полезных ссылок:
- как запускать: https://stackoverflow.com/questions/62564094/c20-coroutines-need-a-function-t...
- код 1: https://godbolt.org/z/Wxhtty
- код 2: https://godbolt.org/z/jTS9BR , https://www.modernescpp.com/index.php/c-20-an-infinite-data-stream-with-corou...
Для Ъ:
// infiniteDataStream.cpp
#include <coroutine>
#include <memory>
#include <iostream>
template<typename T>
struct Generator {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
Generator(handle_type h): coro(h) {} // (3)
handle_type coro;
std::shared_ptr<T> value;
~Generator() {
if ( coro ) coro.destroy();
}
Generator(const Generator&) = delete;
Generator& operator = (const Generator&) = delete;
Generator(Generator&& oth): coro(oth.coro) {
oth.coro = nullptr;
}
Generator& operator = (Generator&& oth) {
coro = oth.coro;
oth.coro = nullptr;
return *this;
}
int getValue() {
return coro.promise().current_value;
}
bool next() { // (5)
coro.resume();
return not coro.done();
}
struct promise_type {
promise_type() = default; // (1)
~promise_type() = default;
auto initial_suspend() { // (4)
return std::suspend_always{};
}
auto final_suspend() {
return std::suspend_always{};
}
auto get_return_object() { // (2)
return Generator{handle_type::from_promise(*this)};
}
auto return_void() {
return std::suspend_never{};
}
auto yield_value(int value) { // (6)
current_value = value;
return std::suspend_always{};
}
void unhandled_exception() {
std::exit(1);
}
T current_value;
};
};
Generator<int> getNext(int start = 0, int step = 1){
auto value = start;
for (int i = 0;; ++i){
co_yield value;
value += step;
}
}
int main() {
std::cout << std::endl;
std::cout << "getNext():";
auto gen = getNext();
for (int i = 0; i <= 10; ++i) {
gen.next();
std::cout << " " << gen.getValue(); // (7)
}
std::cout << "\n\n";
std::cout << "getNext(100, -10):";
auto gen2 = getNext(100, -10);
for (int i = 0; i <= 20; ++i) {
gen2.next();
std::cout << " " << gen2.getValue();
}
std::cout << std::endl;
}
Output:
getNext(): 0 1 2 3 4 5 6 7 8 9 10
getNext(100, -10): 100 90 80 70 60 50 40 30 20 10 0 -10 -20 -30 -40 -50 -60 -70 -80 -90 -100
Исходная версия Kroz, :
Вобщем, я так понял, что это всё еще в экспериментальном состоянии. GCC экспериментально поддерживает в версии 10 (https://gcc.gnu.org/projects/cxx-status.html), clang с версии 9.0. Но я на clang не смог запустить, а десятку GCC вот сечас ставлю.
И там основная хитрость - написать генератор - который по идее должен быть в стандартной библиотек, но пока это не так.
Пару полезных ссылок:
- как запускать: https://stackoverflow.com/questions/62564094/c20-coroutines-need-a-function-t...
- код 1: https://godbolt.org/z/Wxhtty
- код 2: https://godbolt.org/z/jTS9BR , https://www.modernescpp.com/index.php/c-20-an-infinite-data-stream-with-corou...
Для Ъ:
// infiniteDataStream.cpp
#include <coroutine>
#include <memory>
#include <iostream>
template<typename T>
struct Generator {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
Generator(handle_type h): coro(h) {} // (3)
handle_type coro;
std::shared_ptr<T> value;
~Generator() {
if ( coro ) coro.destroy();
}
Generator(const Generator&) = delete;
Generator& operator = (const Generator&) = delete;
Generator(Generator&& oth): coro(oth.coro) {
oth.coro = nullptr;
}
Generator& operator = (Generator&& oth) {
coro = oth.coro;
oth.coro = nullptr;
return *this;
}
int getValue() {
return coro.promise().current_value;
}
bool next() { // (5)
coro.resume();
return not coro.done();
}
struct promise_type {
promise_type() = default; // (1)
~promise_type() = default;
auto initial_suspend() { // (4)
return std::suspend_always{};
}
auto final_suspend() {
return std::suspend_always{};
}
auto get_return_object() { // (2)
return Generator{handle_type::from_promise(*this)};
}
auto return_void() {
return std::suspend_never{};
}
auto yield_value(int value) { // (6)
current_value = value;
return std::suspend_always{};
}
void unhandled_exception() {
std::exit(1);
}
T current_value;
};
};
Generator<int> getNext(int start = 0, int step = 1){
auto value = start;
for (int i = 0;; ++i){
co_yield value;
value += step;
}
}
int main() {
std::cout << std::endl;
std::cout << "getNext():";
auto gen = getNext();
for (int i = 0; i <= 10; ++i) {
gen.next();
std::cout << " " << gen.getValue(); // (7)
}
std::cout << "\n\n";
std::cout << "getNext(100, -10):";
auto gen2 = getNext(100, -10);
for (int i = 0; i <= 20; ++i) {
gen2.next();
std::cout << " " << gen2.getValue();
}
std::cout << std::endl;
}
Output:
getNext(): 0 1 2 3 4 5 6 7 8 9 10
getNext(100, -10): 100 90 80 70 60 50 40 30 20 10 0 -10 -20 -30 -40 -50 -60 -70 -80 -90 -100