Difference between revisions of "cpp/coroutine/generator"
m (WIP, as well as flat_*) |
YexuanXiao (Talk | contribs) m |
||
(37 intermediate revisions by 9 users not shown) | |||
Line 1: | Line 1: | ||
{{cpp/title|generator}} | {{cpp/title|generator}} | ||
{{cpp/coroutine/generator/navbar}} | {{cpp/coroutine/generator/navbar}} | ||
+ | {{dcl begin}} | ||
+ | {{dcl header|generator}} | ||
+ | {{dcl|num=1|since=c++23|1= | ||
+ | template< | ||
+ | class Ref, | ||
+ | class V = void, | ||
+ | class Allocator = void > | ||
+ | class generator | ||
+ | : public ranges::view_interface<generator<Ref, V, Allocator>> | ||
+ | }} | ||
+ | {{dcl|num=2|since=c++23|1= | ||
+ | namespace pmr { | ||
+ | template< class Ref, class V = void > | ||
+ | using generator = | ||
+ | std::generator<Ref, V, std::pmr::polymorphic_allocator<>>; | ||
+ | } | ||
+ | }} | ||
+ | {{dcl end}} | ||
− | {{ | + | @1@ The class template {{tt|std::generator}} presents a {{lconcept|view}} of the elements yielded by the evaluation of a {{lt|cpp/language/coroutines|coroutine}}. |
− | + | ||
− | + | @2@ Convenience alias template for the {{tt|generator}} using the {{lt|cpp/memory/polymorphic allocator}}. | |
− | + | ||
+ | A {{tt|std::generator}} generates a sequence of elements by repeatedly resuming the coroutine from which it was returned. | ||
+ | Each time a {{c/core|co_yield}} statement is evaluated, the coroutine produces one element of the sequence. | ||
+ | When the {{c/core|co_yield}} statement is of the form {{c|co_yield ranges::elements_of(rng)}}, each element of the {{lconcept|range}} {{c|rng}} is successively produced as an element of the sequence. | ||
+ | |||
+ | {{tt|std::generator}} models {{lconcept|view}} and {{lconcept|input_range}}. | ||
+ | |||
+ | The behavior of a program that adds a specialization for {{tt|std::generator}} is undefined. | ||
+ | |||
+ | ===Template parameters=== | ||
+ | {{par begin}} | ||
+ | {{par|Ref|the reference type ({{lc|ranges::range_reference_t}}) of the generator. If {{tt|V}} is {{c/core|void}}, both the reference type and the value type are inferred from {{tt|Ref}}}} | ||
+ | {{par|V|the value type ({{lc|ranges::range_value_t}}) of the generator, or {{c/core|void}}}} | ||
+ | {{par|Allocator|an allocator type or {{c/core|void}}}} | ||
+ | {{par end}} | ||
+ | |||
+ | If {{tt|Allocator}} is not {{c/core|void}}, then the behavior is undefined if {{tt|Allocator}} does not meet the {{named req|Allocator}} requirements. | ||
+ | |||
+ | ===Member types=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc hitem|Member|Definition}} | ||
+ | {{dsc expos mem type|value|private=yes|{{c/core|std::conditional_t<std::is_void_v<V>, std::remove_cvref_t<{{void}}Ref>, V>;}}}} | ||
+ | {{dsc expos mem type|reference|private=yes|{{c/core|std::conditional_t<std::is_void_v<V>, Ref&&, Ref>;}}}} | ||
+ | {{dsc|{{tt|yielded}}|{{box/core|{{c/core|std::conditional_t<std::is_reference_v<}}{{tti|reference}}{{sep}}{{c/core|>,}}{{nbspt|1}}{{tti|reference}}{{c/core|, const}}{{nbspt|1}}{{tti|reference}}{{sep}}{{c/core|&>}}}}}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | {{par begin}} | ||
+ | {{par hreq}} | ||
+ | {{par req|{{c/core|std::allocator_traits<Allocator>::pointer}} is a pointer type.}} | ||
+ | {{par req|{{tti|value}} is a cv-unqualified object type.}} | ||
+ | {{par req|{{tti|reference}} is either a reference type, or a cv-unqualified object type that models {{lconcept|copy_constructible}}.}} | ||
+ | {{par req|Let {{tti|RRef}} denote {{box/core|{{c/core|std::remove_reference_t<}}{{tti|reference}}{{sep}}{{c/core|>&&}}}}, if {{tti|reference}} is a reference type, and {{tti|reference}} otherwise. | ||
+ | * {{box/core|{{c/core|std::common_reference_with<}}{{tti|reference}}{{sep}}{{c/core|&&,}}{{nbspt|1}}{{tti|value}}{{sep}}{{c/core|&>}}}} is modeled. | ||
+ | * {{box/core|{{c/core|std::common_reference_with<}}{{tti|reference}}{{sep}}{{c/core|&&,}}{{nbspt|1}}{{tti|RRef}}{{sep}}{{c/core|&&>}}}} is modeled. | ||
+ | * {{box/core|{{c/core|std::common_reference_with<}}{{tti|RRef}}{{sep}}{{c/core|&&, const}}{{nbspt|1}}{{tti|value}}{{sep}}{{c/core|&>}}}} is modeled. | ||
}} | }} | ||
+ | {{par end}} | ||
+ | |||
+ | The program is ill-formed if any of these type requirements is not satisfied. | ||
+ | |||
+ | ===Data members=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc hitem|Member|Definition}} | ||
+ | {{dsc expos mem obj|active_|private=yes| | ||
+ | Internally, each active instance of {{tt|std::generator}} is associated with a stack (handled as if by object of type {{c/core|std::unique_ptr<std::stack<std::coroutine_handle<>>>}}). | ||
+ | * When {{rlt|begin}} is called, a new stack is created and the generator is added to the stack. | ||
+ | * When {{c|co_yield ranges::elements_of(rng)}} is evaluated in a generator body, {{c|rng}} is converted to a generator and added to the stack that contains the enclosing generator. | ||
+ | * When a generator iterator is {{rl|iterator#increment|incremented}}, the coroutine at the top of the associated stack is resumed. | ||
+ | * When a generator finishes (i.e. when {{l2tt|cpp/coroutine/generator/promise_type/final_suspend}} is called), it is removed from the stack.}} | ||
+ | {{dsc expos mem obj|coroutine_|private=yes|a handle of type {{c/core|std::coroutine_handle<promise_type>}}}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Member functions=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc inc|cpp/coroutine/generator/dsc constructor}} | ||
+ | {{dsc inc|cpp/coroutine/generator/dsc destructor}} | ||
+ | {{dsc inc|cpp/coroutine/generator/dsc operator{{=}}}} | ||
+ | {{dsc inc|cpp/coroutine/generator/dsc begin}} | ||
+ | {{dsc inc|cpp/coroutine/generator/dsc end}} | ||
+ | {{cpp/ranges/view_interface/inherit|embedded=yes|front=invalid|back=invalid|data=invalid|size=invalid|operator[]=invalid}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Nested classes=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc mem class|cpp/coroutine/generator/promise_type|the promise type}} | ||
+ | {{dsc expos mem class|cpp/coroutine/generator/iterator|the iterator type}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Notes=== | ||
+ | {{feature test macro|value=202207L|std=C++23|__cpp_lib_generator|{{ttt|std::generator}} – synchronous {{rlp|/|coroutine}} generator for {{lt|cpp/ranges}}}} | ||
+ | |||
+ | ===Example=== | ||
+ | {{example | ||
+ | |code= | ||
+ | #include <generator> | ||
+ | #include <iostream> | ||
+ | |||
+ | template<typename T> | ||
+ | struct Tree | ||
+ | { | ||
+ | T value; | ||
+ | Tree *left{}, *right{}; | ||
+ | |||
+ | std::generator<const T&> traverse_inorder() const | ||
+ | { | ||
+ | if (left) | ||
+ | co_yield std::ranges::elements_of(left->traverse_inorder()); | ||
+ | |||
+ | co_yield value; | ||
+ | |||
+ | if (right) | ||
+ | co_yield std::ranges::elements_of(right->traverse_inorder()); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | Tree<char> tree[] | ||
+ | { | ||
+ | {'D', tree + 1, tree + 2}, | ||
+ | // │ | ||
+ | // ┌───────────────┴────────────────┐ | ||
+ | // │ │ | ||
+ | {'B', tree + 3, tree + 4}, {'F', tree + 5, tree + 6}, | ||
+ | // │ │ | ||
+ | // ┌─────────┴─────────────┐ ┌───────────┴─────────────┐ | ||
+ | // │ │ │ │ | ||
+ | {'A'}, {'C'}, {'E'}, {'G'} | ||
+ | }; | ||
+ | |||
+ | for (char x : tree->traverse_inorder()) | ||
+ | std::cout << x << ' '; | ||
+ | std::cout << '\n'; | ||
+ | } | ||
+ | |output= | ||
+ | A B C D E F G | ||
+ | }} | ||
+ | |||
+ | ===References=== | ||
+ | {{ref std c++23}} | ||
+ | {{ref std|title=Range generators|id=coro.generator|section=26.8}} | ||
+ | {{ref std end}} | ||
+ | |||
+ | ===See also=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc inc|cpp/coroutine/dsc noop_coroutine}} | ||
+ | {{dsc end}} | ||
− | {{ | + | {{langlinks|es|ja|ru|zh}} |
Latest revision as of 21:38, 12 November 2024
Defined in header <generator>
|
||
template< class Ref, |
(1) | (since C++23) |
namespace pmr { template< class Ref, class V = void > |
(2) | (since C++23) |
std::generator
presents a view
of the elements yielded by the evaluation of a coroutine.A std::generator
generates a sequence of elements by repeatedly resuming the coroutine from which it was returned.
Each time a co_yield statement is evaluated, the coroutine produces one element of the sequence.
When the co_yield statement is of the form co_yield ranges::elements_of(rng), each element of the range
rng is successively produced as an element of the sequence.
std::generator
models view
and input_range
.
The behavior of a program that adds a specialization for std::generator
is undefined.
Contents |
[edit] Template parameters
Ref | - | the reference type (ranges::range_reference_t) of the generator. If V is void, both the reference type and the value type are inferred from Ref
|
V | - | the value type (ranges::range_value_t) of the generator, or void |
Allocator | - | an allocator type or void |
If Allocator
is not void, then the behavior is undefined if Allocator
does not meet the Allocator requirements.
[edit] Member types
Member | Definition |
value (private)
|
std::conditional_t<std::is_void_v<V>, std::remove_cvref_t<Ref>, V>; (exposition-only member type*) |
reference (private)
|
std::conditional_t<std::is_void_v<V>, Ref&&, Ref>; (exposition-only member type*) |
yielded
|
std::conditional_t<std::is_reference_v<reference >, reference , const reference &>
|
Type requirements | ||
-std::allocator_traits<Allocator>::pointer is a pointer type. | ||
-value is a cv-unqualified object type.
| ||
-reference is either a reference type, or a cv-unqualified object type that models copy_constructible .
| ||
-Let RRef denote std::remove_reference_t<reference >&&, if reference is a reference type, and reference otherwise.
|
The program is ill-formed if any of these type requirements is not satisfied.
[edit] Data members
Member | Definition |
active_ (private)
|
Internally, each active instance of
|
coroutine_ (private)
|
a handle of type std::coroutine_handle<promise_type> (exposition-only member object*) |
[edit] Member functions
constructs a generator object (public member function) | |
effectively destroys the entire stack of yielded generator s (public member function) | |
assigns a generator object (public member function) | |
resumes the initially suspended coroutine and returns an iterator to its handle (public member function) | |
returns std::default_sentinel (public member function) | |
Inherited from std::ranges::view_interface | |
returns whether the derived view is empty. Provided if it satisfies sized_range or forward_range . (public member function of std::ranges::view_interface<D> )
| |
(C++23) |
returns a constant iterator to the beginning of the range. (public member function of std::ranges::view_interface<D> )
|
(C++23) |
returns a sentinel for the constant iterator of the range. (public member function of std::ranges::view_interface<D> )
|
returns whether the derived view is not empty. Provided if ranges::empty is applicable to it. (public member function of std::ranges::view_interface<D> )
|
[edit] Nested classes
the promise type (public member class) | |
the iterator type (exposition-only member class*) |
[edit] Notes
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_lib_generator |
202207L | (C++23) | std::generator – synchronous coroutine generator for ranges
|
[edit] Example
#include <generator> #include <iostream> template<typename T> struct Tree { T value; Tree *left{}, *right{}; std::generator<const T&> traverse_inorder() const { if (left) co_yield std::ranges::elements_of(left->traverse_inorder()); co_yield value; if (right) co_yield std::ranges::elements_of(right->traverse_inorder()); } }; int main() { Tree<char> tree[] { {'D', tree + 1, tree + 2}, // │ // ┌───────────────┴────────────────┐ // │ │ {'B', tree + 3, tree + 4}, {'F', tree + 5, tree + 6}, // │ │ // ┌─────────┴─────────────┐ ┌───────────┴─────────────┐ // │ │ │ │ {'A'}, {'C'}, {'E'}, {'G'} }; for (char x : tree->traverse_inorder()) std::cout << x << ' '; std::cout << '\n'; }
Output:
A B C D E F G
[edit] References
- C++23 standard (ISO/IEC 14882:2024):
- 26.8 Range generators [coro.generator]
[edit] See also
(C++20) |
creates a coroutine handle that has no observable effects when resumed or destroyed (function) |