Spec-Zone.ru › C++

std::coroutine_handle, std::noop_coroutine_handle

Определено в заголовочном файле <coroutine>
template< class Promise = void >
struct coroutine_handle;
(1) (начиная с C++20)
template<>
struct coroutine_handle<void>;
(2) (начиная с C++20)
template<>
struct coroutine_handle<std::noop_coroutine_promise>;
(3) (начиная с C++20)
using noop_coroutine_handle =
    std::coroutine_handle<std::noop_coroutine_promise>;
(4) (начиная с C++20)

Шаблон класса coroutine_handle можно использовать для ссылки на приостановленную или выполняющуюся корутину. Каждая специализация coroutine_handle является LiteralType.

1) Основной шаблон; может быть создан из объекта promise типа Promise.
2) Специализация std::coroutine_handle<void> стирает тип promise. Она допускает преобразование из других специализаций.
3) Специализация std::coroutine_handle<std::noop_coroutine_promise> ссылается на корутины без операций. Её нельзя создать из объекта promise.

В типичных реализациях каждая специализация std::coroutine_handle является TriviallyCopyable.

Если программа добавляет специализации для std::coroutine_handle, поведение не определено.

Поля

Имя поля Определение
ptr (закрытое) Указатель void* на состояние корутины.
(элемент-объект только для пояснения*)

Функции-члены

(конструктор)
создаёт объект coroutine_handle
(открытая функция-член)
operator=
присваивает значение объекту coroutine_handle
(открытая функция-член)
Преобразование
operator coroutine_handle<>
получает coroutine_handle со стёртым типом
(открытая функция-член)
Наблюдатели
done
проверяет, завершилась ли корутина
(открытая функция-член)
operator bool
проверяет, представляет ли дескриптор корутину
(открытая функция-член)
Управление
operator()resume
возобновляет выполнение корутины
(открытая функция-член)
destroy
уничтожает корутину
(открытая функция-член)
Доступ к promise
promise
обращается к promise корутины
(открытая функция-член)
from_promise
[статическая]
создаёт coroutine_handle из объекта promise корутины
(открытая статическая функция-член)
Экспорт/импорт
address
экспортирует базовый адрес, то есть указатель, лежащий в основе корутины
(открытая функция-член)
from_address
[статическая]
импортирует корутину из указателя
(открытая статическая функция-член)

Функции, не являющиеся членами

operator==operator<=>
(C++20)
сравнивает два объекта coroutine_handle
(функция)

Вспомогательные классы

std::hash<std::coroutine_handle>
(C++20)
поддержка хеширования для std::coroutine_handle
(специализация шаблона класса)

Примечания

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

Пример

#include <coroutine>
#include <iostream>
#include <optional>

template<std::movable T>
class Generator
{
public:
    struct promise_type
    {
        Generator<T> get_return_object()
        {
            return Generator{Handle::from_promise(*this)};
        }
        static std::suspend_always initial_suspend() noexcept
        {
            return {};
        }
        static std::suspend_always final_suspend() noexcept
        {
            return {};
        }
        std::suspend_always yield_value(T value) noexcept
        {
            current_value = std::move(value);
            return {};
        }
        // Disallow co_await in generator coroutines.
        void await_transform() = delete;
        [[noreturn]]
        static void unhandled_exception() { throw; }

        std::optional<T> current_value;
    };

    using Handle = std::coroutine_handle<promise_type>;

    explicit Generator(const Handle coroutine) :
        m_coroutine{coroutine}
    {}

    Generator() = default;
    ~Generator()
    {
        if (m_coroutine)
            m_coroutine.destroy();
    }

    Generator(const Generator&) = delete;
    Generator& operator=(const Generator&) = delete;

    Generator(Generator&& other) noexcept :
        m_coroutine{other.m_coroutine}
    {
        other.m_coroutine = {};
    }
    Generator& operator=(Generator&& other) noexcept
    {
        if (this != &other)
        {
            if (m_coroutine)
                m_coroutine.destroy();
            m_coroutine = other.m_coroutine;
            other.m_coroutine = {};
        }
        return *this;
    }

    // Range-based for loop support.
    class Iter
    {
    public:
        void operator++()
        {
            m_coroutine.resume();
        }
        const T& operator*() const
        {
            return *m_coroutine.promise().current_value;
        }
        bool operator==(std::default_sentinel_t) const
        {
            return !m_coroutine || m_coroutine.done();
        }

        explicit Iter(const Handle coroutine) :
            m_coroutine{coroutine}
        {}

    private:
        Handle m_coroutine;
    };

    Iter begin()
    {
        if (m_coroutine)
            m_coroutine.resume();
        return Iter{m_coroutine};
    }

    std::default_sentinel_t end() { return {}; }

private:
    Handle m_coroutine;
};

template<std::integral T>
Generator<T> range(T first, const T last)
{
    while (first < last)
        co_yield first++;
}

int main()
{
    for (const char i : range(65, 91))
        std::cout << i << ' ';
    std::cout << '\n';
}

Вывод:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.

DR Применяется к Опубликованное поведение Корректное поведение
LWG 3460 C++20 открытый базовый класс coroutine_handle мог оставлять его в нежелательном состоянии наследование удалено

См. также

generator
(C++23)
view, представляющий генератор синхронных корутин
(шаблон класса)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/coroutine/coroutine_handle

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API