C++ 查找 co_await 可等待的结果类型

C++ find co_await awaitable result type

我想知道是否可以找到 awaitable 的 co_await 结果类型: 由于无法在未评估的上下文中使用 co_await,因此我无法执行

template<class Awaitable>
task<> f(Awaitable&& awaitable)
{
  using result_type = decltype(co_await awaitable);
}

有什么办法可以做到吗?

这里的主要目的是确定 result_type 是否无效,这基本上就是我们所拥有的:我们想要 fire_and_forget 一个任务,并在完成时调用一个方法,但是由于 void return 类型,这并不容易

template<class Awaitable, class Success, class Failure >
detail::fire_and_forget_task call_async_then(Awaitable awaitable, Success success, Failure failure)
{
  try
  {
    using result_type = ??
    if constexpr (std::is_same_v<void, result_t>)
    {
      co_await awaitable;
      success();
    }
    else
      success(co_await f);
  }
  catch(...)
  {
    failure(std::current_exception());
  }
}

也许有更简单的方法,但目前我还没有想到。

谢谢

通常没有办法做到这一点,因为 co_awaitcoroutine machinery 部分依赖于调用 承诺类型 的函数 co_await。当调用 co_await <expr> 时,它必须将 <expr> 转换为可等待类型。该过程的一部分涉及询问协同程序的承诺类型,如果它愿意的话,可以对这种转换进行权衡。由于 promise 类型是由协程的签名定义的,因此任何 co_await <expr> 的结果类型都取决于调用它的函数的签名。

这就是为什么 co_await 不能在未计算的上下文中使用的原因;它的行为依赖于上下文.

现在,如果您知道您的承诺类型没有await_transform(您可能知道,因为它是您的 promise 类型),则可以计算结果类型。 co_await <expr> 的等待类型将只是 <expr> 的类型。然后通过在表达式上调用 operator co_await 将其转换为 awaiter 对象。这有点难以计算,因为它可以通过成员函数或非成员运算符调用来调用,因此元编程有点棘手。

一旦有了awaiter对象类型,就可以获得其await_resume()的return类型;这是 co_await <expr> 表达式的类型。

好的,非常感谢,现在我明白为什么 decltype(co_await awaitable) 不被允许的原因了。 因此,如果我理解得很好,并且如果我从 https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await 中获取伪代码以从可等待类型中获取等待者(假设我跳过非成员运算符以进行简化),我可以获得这样的结果(也许有一些更简单的东西我不习惯写检测惯用语):

#include <type_traits>

template< class, class = std::void_t<> >
struct has_co_await_operator : std::false_type
{};

template< class T >
struct has_co_await_operator< T, std::void_t< decltype(std::declval<T>().operator co_await()) > >
    : std::true_type
{};

template< class T >
constexpr bool has_co_await_operator_v = has_co_await_operator<T>::value;

template< class T >
struct get_awaiter : std::conditional< has_co_await_operator_v<T>, decltype(std::declval<T>().operator co_await()), T>
{};

template<class T>
using get_awaiter_t = typename get_awaiter<T>::type;

template<class Awaitable>
struct awaitable_result
{
    using type = decltype(std::declval<get_awaiter_t<Awaitable>>().await_resume());
};

template<class T>
using awaitable_result_t = typename awaitable_result<T>::type;

https://godbolt.org/z/dAVfVX

你觉得还好吗?