::from_promise(*p) h.destroy() // удаляет CoroutineState }
Future(promise_type* p) : promise(p, Deleter) {}
Y BlockingGet() { while (promise->y_ptr == nullptr) Sleep(1) // ждем return *promise->y_ptr // дождались вызова p.return_value(y) } }
Future::promise_type должен иметь get_return_object, initial_suspend, final_suspend и либо return_void либо return_value.
Для реализации initial_suspend и final_suspend можно использовать стандартные suspend_never и suspend_always, которые возвращают в await_ready значения true и false соответственно.
Такая сопрограмма будет всегда засыпать в конце.
От самого Future требуется только чтобы он удалил сопрограмму через h.destroy().
Future может (но не обязан) повторять интерфейс Awaiter, чтобы быть совместимым с co_await.
await_transform и operator co_await
Для выражения a в co_await a могут применяться дополнительные преобразования:
если выражение p.await_transform(a) валидно, то a заменяется на p.await_transform(a) если для типа a есть оператор operator co_await, то a заменяется на operator co_await(a) если в результате получилось prvalue, то оно копируется во временную переменную, иначе используется как есть.
Таким образом возможен вариант
auto& e = operator co_await(p.await_transform(f(x))) if (!e.await_ready()) { ... }
Например можно определить operator co_await(std::chrono::duration) и писать co_await 10ms .
Выделение памяти
Объект CoroutineState создается при помощи new. Однако, если есть функция p.get_return_object_on_allocation_failure(), то будет сгенерирован следующий код:
auto* s = new(std::nothrow) CoroutineState if (!s) { return p.get_return_object_on_allocation_failure() } auto result = s->p.get_return_object()
Это позволяет обрабатывать ошибки выделения памяти.
Также, аргументы сопрограммы могут участвовать в выделении памяти. Для сопрограммы Future coro(A1 a1, A2 a2), если есть функция operator new(std::size_t, A1, A2), то она будет вызвана вместо оператора new по умолчанию.
promise_type (ч.3), coroutine_traits
Компилятор использует класс coroutine_traits для получения promise_type.
Для сопрограммы Future coro(A1 a1, A2 a2) будет использован тип std::experimental::coroutine_traits::promise_type.
Реализация по-умолчанию выдает Future::promise_type, однако это может быть переопределено пользователем.
co_yield
co_yield e эквивалентен co_await p.yield_value(e) и используется в генераторах - специальных сопрограммах которые предназначены для выдачи последовательности значений.
Примеры
Как использовать сопрограммы С++ с Boost.Asio?