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_await
的 coroutine 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;
你觉得还好吗?
我想知道是否可以找到 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_await
的 coroutine 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;
你觉得还好吗?