Espacios de nombres
Variantes
Acciones

std::coroutine_traits

De cppreference.com
< cpp‎ | coroutine
 
 
Biblioteca de servicios
 
Apoyo de corrutinas
Rasgos de corrutinas
coroutine_traits
(C++20)
Identificador de corrutina
Corrutinas no operativas
En espera triviales
 
Definido en el archivo de encabezado <coroutine>
template< class R, class... Args >
struct coroutine_traits;
(desde C++20)

Determina el tipo de promesa a partir del tipo de retorno y los tipos de los parámetros de una corrutina. La biblioteca estándar proporciona un tipo miembro públicamente accesible promise_type igual que R::promise_type si el id-calificado es válido y denota un tipo; de lo contrario, no tiene tal miembro.

Las especializaciones definidas por el programa de coroutine_traits deberán definir un tipo miembro públicamente accesible promise_type; de lo contrario, el comportamiento no está definido.

Contenido

[editar] Parámetros de plantilla

R - Tipo de retorno de la corrutina.
Args - Los tipos de los parámetros de la corrutina, incluyendo el parámetro objeto implícito parámetro objeto implícito si la corrutina es una función miembro no estática.

[editar] Tipos miembro

Tipo Definición
promise_type R::promise_type si es válido, o proporcionado por las especializaciones definidas por el programa.

[editar] Posible implementación

template<class, class...>
struct coroutine_traits {};
 
template<class R, class... Args>
    requires requires { typename R::promise_type }
struct coroutine_traits<R, Args...> {
    using promise_type = R::promise_type;
};

[editar] Notas

Si la corrutina es una función miembro no estática, entonces el primer tipo en Args... es el tipo del parámetro objeto implícito, y el resto son los tipos de los parámetros de la función (si los hay).

Si std::coroutine_traits<R, Args...>::promise_type no existe o no es un tipo clase, la definición correspondiente de la corrutina está mal formada.

Los usuarios pueden definir especializaciones parciales o explícitas (totales) de coroutine_traits dependientes de los tipos definidos por el programa para evitar la modificación a los tipos de retorno.

[editar] Ejemplo

#include <chrono>
#include <coroutine>
#include <exception>
#include <future>
#include <iostream>
#include <thread>
#include <type_traits>
 
// Habilitar el uso de std::future<T> como un tipo corrutina
// usando a std::promise<T> como el tipo promesa.
template <typename T, typename... Args>
requires(!std::is_void_v<T> && !std::is_reference_v<T>)
struct std::coroutine_traits<std::future<T>, Args...> {
  struct promise_type : std::promise<T> {
    std::future<T> get_return_object() noexcept {
      return this->get_future();
    }
 
    std::suspend_never initial_suspend() const noexcept { return {}; }
    std::suspend_never final_suspend() const noexcept { return {}; }
 
    void return_value(const T &value)
    noexcept(std::is_nothrow_copy_constructible_v<T>) {
      this->set_value(value);
    }
    void return_value(T &&value)
    noexcept(std::is_nothrow_move_constructible_v<T>) {
      this->set_value(std::move(value));
    }
    void unhandled_exception() noexcept {
      this->set_exception(std::current_exception());
    }
  };
};
 
// Lo mismo para std::future<void>.
template <typename... Args>
struct std::coroutine_traits<std::future<void>, Args...> {
  struct promise_type : std::promise<void> {
    std::future<void> get_return_object() noexcept {
      return this->get_future();
    }
 
    std::suspend_never initial_suspend() const noexcept { return {}; }
    std::suspend_never final_suspend() const noexcept { return {}; }
 
    void return_void() noexcept {
      this->set_value();
    }
    void unhandled_exception() noexcept {
      this->set_exception(std::current_exception());
    }
  };
};
 
// Permitir la espera con co_await para std::future<T> y std::future<void>
// ingenuamente iniciando un nuevo hilo para cada co_await.
template <typename T>
auto operator co_await(std::future<T> future) noexcept
requires(!std::is_reference_v<T>) {
  struct awaiter : std::future<T> {
    bool await_ready() const noexcept {
      using namespace std::chrono_literals;
      return this->wait_for(0s) != std::future_status::timeout;
    }
    void await_suspend(std::coroutine_handle<> cont) const {
      std::thread([this, cont] {
        this->wait();
        cont();
      }).detach();
    }
    T await_resume() { return this->get(); }
  };
  return awaiter{std::move(future)};
}
 
// Utilizar la infraestructura que hemos establecido.
std::future<int> compute() {
  int a = co_await std::async([] { return 6; });
  int b = co_await std::async([] { return 7; });
  co_return a * b;
}
 
std::future<void> fail() {
  throw std::runtime_error("fuchi");
  co_return;
}
 
int main() {
  std::cout << compute().get() << '\n';
 
  try {
    fail().get();
  } catch (const std::runtime_error &e) {
    std::cout << "error: " << e.what() << '\n';
  }
}

Salida:

42
error: fuchi