【问题标题】:C++ find co_await awaitable result typeC++ 查找 co_await 等待结果类型
【发布时间】:2020-07-31 02:29:12
【问题描述】:

我想知道是否可以找到等待的 co_await 的结果类型: 由于不可能在未评估的上下文中使用 co_await,我不能这样做

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

有什么办法可以做到吗?

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

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

也许有更简单的方法可以做到,但现在我没有想到任何方法。

谢谢

【问题讨论】:

    标签: c++ c++20 c++-coroutine


    【解决方案1】:

    通常没有办法这样做,因为co_awaitcoroutine machinery 部分依赖于调用co_await 的函数的承诺类型。当调用 co_await &lt;expr&gt; 时,它必须将 &lt;expr&gt; 转换为可等待类型。该过程的一部分涉及要求协程的承诺类型在此转换中权衡(如果它愿意)。由于 promise 类型是由协程的签名定义的,因此任何 co_await &lt;expr&gt; 的结果类型都依赖于调用它的函数的签名。

    这就是为什么co_await 不能在未评估的上下文中使用的原因;它的行为与上下文相关

    现在,如果您知道您的承诺类型没有await_transform(您可能知道,因为它是您的承诺类型),那么结果类型是可以计算的。 co_await &lt;expr&gt; 的可等待类型将只是 &lt;expr&gt; 的类型。然后通过在表达式上调用 operator co_await 将其转换为等待者对象。这有点难以计算,因为它可以通过成员函数或非成员运算符调用来调用,所以它是元编程的一个棘手部分。

    一旦有了awaiter对象类型,就可以得到它的await_resume()的返回类型;这是co_await &lt;expr&gt; 表达式的类型。

    【讨论】:

      【解决方案2】:

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

      #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

      你觉得还可以吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-30
        • 2021-02-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多