std::coroutine_traits - cppreference.com
Espacios de nombres
Variantes

std::coroutine_traits

De cppreference.com
 
 
Biblioteca de servicios
Apoyo del lenguaje
Apoyo de tipos (tipos básicos, RTTI)
Macros de prueba de característica de la biblioteca (C++20)
Servicios de programa
Funciones variádicas
Apoyo de corrutinas (C++20)
Apoyo de contratos (C++26)
Comparación de tres vías (C++20)
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

 
Apoyo de corrutinas
Rasgos de corrutinas
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.

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.

Tipos miembro

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

Posible implementación

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.

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