Я пытаюсь понять, как именно новые сопрограммы работают в C ++ 20, но кроме очень тривиальных примеров я не могу заставить их работать.
Моя цель - создать глубокие вложенные функции, которые позволяют можно сломать и вернуть управление большей части внешнего кода, а после некоторого условия он вернет управление этой внутренней функции. Это эффективно setjmp
и longjmp
.
Я испортил код, используя некоторые примеры, найденные в net:
#include <iostream>
#include <coroutine>
#include <optional>
template <typename T>
struct task
{
struct task_promise;
using promise_type = task_promise;
using handle_type = std::coroutine_handle<promise_type>;
mutable handle_type m_handle;
task(handle_type handle)
: m_handle(handle)
{
}
task(task&& other) noexcept
: m_handle(other.m_handle)
{
other.m_handle = nullptr;
}
bool await_ready()
{
return m_handle.done();
}
bool await_suspend(std::coroutine_handle<> handle)
{
if (!m_handle.done()) {
m_handle.resume();
}
return !m_handle.done();
}
auto await_resume()
{
return result();
}
T result() const
{
if (!m_handle.done())
m_handle.resume();
return *m_handle.promise().m_value;
}
//manualy wait for finish
bool one_step()
{
if (!m_handle.done())
m_handle.resume();
return !m_handle.done();
}
~task()
{
if (m_handle)
m_handle.destroy();
}
struct task_promise
{
std::optional<T> m_value {};
auto value()
{
return m_value;
}
auto initial_suspend()
{
return std::suspend_always{};
}
auto final_suspend()
{
return std::suspend_always{};
}
auto return_value(T t)
{
m_value = t;
return std::suspend_always{};
}
task<T> get_return_object()
{
return {handle_type::from_promise(*this)};
}
void unhandled_exception()
{
std::terminate();
}
void rethrow_if_unhandled_exception()
{
}
};
};
static task<int> suspend_one()
{
std::cout<< "suspend_one in\n";
co_await std::suspend_always();
std::cout<< "suspend_one return\n";
co_return 1;
}
static task<int> suspend_two()
{
std::cout<< "suspend_two -> suspend_one #1\n";
auto a = co_await suspend_one();
std::cout<< "suspend_two -> suspend_one #2\n";
auto b = co_await suspend_one();
std::cout<< "suspend_two return\n";
co_return a + b;
}
static task<int> suspend_five()
{
std::cout<< "suspend_five -> suspend_two #1\n";
auto a = co_await suspend_two();
std::cout<< "suspend_five -> suspend_one #2\n";
auto b = co_await suspend_one();
std::cout<< "suspend_five -> suspend_two #3\n";
auto c = co_await suspend_two();
std::cout<< "suspend_five return\n";
co_return a + b + c;
}
static task<int> run()
{
std::cout<< "run -> suspend_two #1\n";
auto a = co_await suspend_two();
std::cout<< "run -> suspend_one #2\n";
auto b = co_await suspend_one();
std::cout<< "run -> suspend_five #3\n";
auto c = co_await suspend_five();
std::cout<< "run -> suspend_one #4\n";
auto d = co_await suspend_one();
std::cout<< "run -> suspend_two #5\n";
auto e = co_await suspend_two();
std::cout<< "run return\n";
co_return a + b + c + d + e;
}
int main()
{
std::cout<< "main in\n";
auto r = run();
std::cout<< "main -> while\n";
while (r.one_step()){ std::cout<< "<<<< while loop\n"; }
std::cout<< "main return\n";
return r.result();
}
https://gcc.godbolt.org/z/JULJCi
Функция run
работает должным образом, но у меня проблема, например, с suspend_five
, где она никогда не достигает строки
std::cout<< "suspend_five -> suspend_two #3\n";
Вероятно, моя версия task
полностью не работает, но я понятия не имею, где найдите эту ошибку или как она должна выглядеть. Или просто то, чего я хочу достичь, не поддерживается C ++ 20? co_yeld
может быть кандидатом для обхода, потому что кажется более возможным вложить их вручную (for (auto z : f()) co_yeld z;
), но цель этого вопроса - понять внутренний механизм c функциональности C ++ 20, который решает некоторые существующие проблемы.