Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ find co_await awaitable result type

I would like to know if it is possible to find the result type of co_await of an awaitable: As it is not possible to use co_await in an unevaluated context, I cannot do

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

Is there any way this can be done ?

The main purpose here is do determine wether or not the result_type is void, here is basically what we have: we would like to fire_and_forget a task, and call a method on completion, but because of void return type, it's not that easy

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());
  }
}

Maybe there a simpler way to do it, but right now I don't think of any.

Thank you

like image 273
Victor Burckel Avatar asked Apr 17 '20 14:04

Victor Burckel


1 Answers

There is no way to do this generally because co_await's coroutine machinery is in part dependent on the promise type for the function that invokes co_await. When a co_await <expr> is invoked, it will have to transform <expr> into an awaitable type. Part of that process involves asking the promise type for the coroutine to weigh in on this conversion if it so chooses. Since the promise type is defined by the signature of the coroutine, the result type of any co_await <expr> is therefore dependent on the signature of the function invoking it.

This is why co_await cannot be used in an unevaluated context; it's behavior is context-dependent.

Now, if you know that your promise type does not have await_transform (which you probably do know, since it's your promise type), then the result type is possible to compute. The awaitable type for co_await <expr> will just be the type of <expr>. This is then converted into an awaiter object via invoking operator co_await on the expression. That's a bit difficult to compute, as it could be invoked via a member function or a non-member operator call, so it's a tricky bit of metaprogramming.

Once you have the awaiter object type, you can get the return type of its await_resume(); this is the type of the co_await <expr> expression.

like image 85
Nicol Bolas Avatar answered Sep 26 '22 00:09

Nicol Bolas