libtuil: allow non-default-constructible types in generators

references remain forbidden because std::optional does not want to
contain them, and specializing generators to use pointers where we
can't use optionals is simply too much work for a feature we don't
even need. reference wrappers and bindings still work well enough.

Change-Id: I2e6ca74719584ce16e2357c452fdd5c5a9e23d5a
This commit is contained in:
eldritch horrors
2025-01-19 16:40:26 +01:00
parent b8ab642fdf
commit 10104b8ac1
2 changed files with 20 additions and 4 deletions
+4 -4
View File
@@ -39,9 +39,9 @@ struct failure
template<typename T>
struct promise_state
{
// result of the most recent coroutine resumption: a value,
// a nested coroutine to drain, an error, or our completion
std::variant<T, link<T>, failure, finished> value{};
// result of the most recent coroutine resumption: a nested
// coroutine to drain, a value, an error, or our completion
std::variant<link<T>, T, failure, finished> value{};
// coroutine to resume when this one has finished. set when
// one generator yields another, such that the entire chain
// of parents always linearly points to the root generator.
@@ -86,7 +86,7 @@ struct promise : promise_state<T>
}
std::suspend_always yield_value(From && from)
{
this->value.template emplace<0>(convert(std::forward<From>(from)));
this->value.template emplace<1>(convert(std::forward<From>(from)));
return {};
}
+16
View File
@@ -260,4 +260,20 @@ TEST(Generator, iterators)
}
}
TEST(Generator, nonDefaultCtor)
{
auto g = []() -> Generator<std::reference_wrapper<int>> {
int i = 0;
co_yield i;
i += 1;
co_yield i;
}();
auto i = g.next();
ASSERT_EQ(*i, 0);
i->get() = 10;
i = g.next();
ASSERT_EQ(*i, 11);
}
}