Почему шаблон не отбрасывает co_return?
Я хотел бы сделать функцию как с синхронизацией, так и с версией сопрограммы, без использования специализации шаблона, т.е. с
if constexpr
.
Это функция, которую я написал:
template <Async _a>
AsyncResult<int, _a> func(int a) {
if constexpr (_a == Async::Disable)
return a;
else
co_return a;
}
Но когда я создаю истинную ветку, она выдает ошибку
auto a = func<Async::Disable>(1); // compiler error
auto b = func<Async::Enable>(2); // ok
error: unable to find the promise type for this coroutine
Почему это не работает?
2 ответа
Стандарт прямо говорит, что это невозможно. Согласно примечанию 1 в stmt.return.coroutine#1
... Сопрограмма не должна содержать оператор возврата ([stmt.return]).
[Примечание 1: Для этого определения не имеет значения, заключен ли оператор return в оператор отбрасывания ([stmt.if]). — примечание в конце]
Таким образом, вы не сможете вернуться из сопрограммы, даже если она находится в отброшенном операторе. Вы можете специализировать шаблон функции вместо использования
if constexpr
.
template <Async _a>
AsyncResult<int, _a> func(int a)
{
co_return a;
}
template <>
AsyncResult<int, Async::Disable> func<Async::Disable>(int a)
{
return a;
}
Вот демо .
Функция, которая имеет
co_return
/
co_await
/
co_yield
оператор в нем безоговорочно является сопрограммой, даже если он отбрасывается
if constexpr
.
У вас должно быть 2 разные функции. Вот некоторые вещи, которые вы могли бы сделать:
// Have the second function be a lambda:
template <Async _a>
AsyncResult<int, _a> func(int a) {
if constexpr (_a == Async::Disable)
return a;
else
return ([](int a) -> AsyncResult<int, _a> {
co_return a;
})(a);
}
// Have the second function be a helper function
namespace detail {
AsyncResult<int, Async::Enable> async_enable_func(int a) {
co_return a;
}
}
template <Async _a>
AsyncResult<int, _a> func(int a) {
if constexpr (_a == Async::Disable)
return a;
else
return detail::async_enable_func(a);
}
// Have the second function be an overload
template <Async _a> requires (_a == Async::Disable)
AsyncResult<int, _a> func(int a) {
return a;
}
template <Async _a> requires (_a == Async::Enable)
AsyncResult<int, _a> func(int a) {
co_return a;
}
// Since you only have 1 template parameter, you can fully specialize
template<Async _a>
AsyncResult<int, _a> func(int a) {
return a;
}
template<>
AsyncResult<int, Async::Enable> func<Async::Enable>(int a) {
co_return a;
}