This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
co_yield elements_of(vector<int>()) does not compileSection: 25.8.5 [coro.generator.promise] Status: New Submitter: Mathias Stearn Opened: 2025-10-16 Last modified: 2025-10-23
Priority: 2
View all other issues in [coro.generator.promise].
View all issues with New status.
Discussion:
The std::generator proposal (P2502) explicitly says that the following example is supposed to work, but it does not compile:
For convenience, we further propose that
co_yield elements_of(x)be extended to support yielding the values of arbitrary ranges beyond generators, iestd::generator<int> f() { std::vector<int> v = /*... */; co_yield std::ranges::elements_of(v); }
This doesn't compile because the overload listed in 25.8.5 [coro.generator.promise] p13
requires convertible_to<ranges::range_reference_t<R>, yielded> (i.e.
convertible_to<int&, int&&>) which isn't satisfied.
co_yield elements_of(rng) should be
semantically similar to the following code, but require a specific optimization in the
case where rng is the same type of generator as the current coroutine:
for (auto&& x : rng) {
co_yield std::forward<decltype(x)>(x);
}
Note that that code does compile correctly where rng is a vector<int>, so
I think the original code should as well.
generator<T>
in P2502R0 was basically the same as generator<const T&> where
co_yield elements_of(vector<int>()) does work. After P2529 (which was a
design paper w/o wording) was approved by LEWG, P2502R1 was updated to change the
reference type to T&&. However, when making the change, I assume that the impact
it had on the elements_of-non-generator overload of yield_value was not considered, so it was
unmodified.
[2025-10-23; Reflector poll.]
Set priority to 2 after reflector poll.
The current resolution is incorrect, and breaks following example:
std::generator<std::vector<int>> g()
{
std::vector<int> v = {1, 2, 3};
co_yield std::ranges::elements_of(v);
}
The constraints are equivalent to checking if yield_value(*it) is well-formed,
and maybe we could express is directly as:
requires requires (promise_type p, ranges::iterator_t<R> it) {
p.yield_value(*it);
}
Proposed resolution:
This wording is relative to N5014.
Modify 25.8.5 [coro.generator.promise] as indicated:
[Drafting note: The following changes would check that
co_yield *iwould match one of the overloads ofyield_value()described in paragraphs 4 or 6. Alternatively this could be expressed more directly as a helper comment or in prose in a Mandates: element.
[…]namespace std { template<class Ref, class Val, class Allocator> class generator<Ref, Val, Allocator>::promise_type { public: […] template<ranges::input_range R, class Alloc> requires convertible_to<ranges::range_reference_t<R>, yielded> || (is_rvalue_reference_v<yielded> && constructible_from<remove_cvref_t<yielded>, const remove_reference_t<yielded>&>) auto yield_value(ranges::elements_of<R, Alloc> r); […] }; }template<ranges::input_range R, class Alloc> requires convertible_to<ranges::range_reference_t<R>, yielded> || (is_rvalue_reference_v<yielded> && constructible_from<remove_cvref_t<yielded>, const remove_reference_t<yielded>&>) auto yield_value(ranges::elements_of<R, Alloc> r);-13- Effects: Equivalent to:
auto nested = [](allocator_arg_t, Alloc, ranges::iterator_t<R> i, ranges::sentinel_t<R> s) -> generator<yielded, void, Alloc> { for (; i != s; ++i) { co_yieldstatic_cast<yielded>(*i); } }; return yield_value(ranges::elements_of(nested( allocator_arg, r.allocator, ranges::begin(r.range), ranges::end(r.range))));