9.9 KiB
[expr.await]
7 Expressions [expr]
7.6 Compound expressions [expr.compound]
7.6.2 Unary expressions [expr.unary]
7.6.2.4 Await [expr.await]
The co_await expression is used to suspend evaluation of a coroutine ([dcl.fct.def.coroutine]) while awaiting completion of the computation represented by the operand expression.
Suspending the evaluation of a coroutine transfers control to its caller or resumer.
await-expression:
co_await cast-expression
An await-expression shall appear only as a potentially-evaluated expression within the compound-statement of afunction-body or lambda-expression, in either case outside of a handler ([except.pre]).
In a declaration-statement or in thesimple-declaration (if any) of an init-statement, an await-expression shall appear only in an initializer of thatdeclaration-statement or simple-declaration.
An await-expression shall not appear in a default argument ([dcl.fct.default]).
An await-expression shall not appear in the initializer of a block variable with static or thread storage duration.
An await-expression shall not be a potentially-evaluated subexpression of the predicate of a contract assertion ([basic.contract]).
A context within a function where an await-expression can appear is called a suspension context of the function.
Evaluation of an await-expression involves the following auxiliary types, expressions, and objects:
-
p is an lvalue naming the promise object ([dcl.fct.def.coroutine]) of the enclosing coroutine and P is the type of that object.
-
Unless the await-expression was implicitly produced by a yield-expression ([expr.yield]), an initial await expression, or a final await expression ([dcl.fct.def.coroutine]), a search is performed for the name await_transform in the scope of P ([class.member.lookup]). If this search is performed and finds at least one declaration, then a isp.await_transform(cast-expression); otherwise, a is the cast-expression.
-
o is determined by enumerating the applicableoperator co_await functions for an argumenta ([over.match.oper]), and choosing the best one through overload resolution ([over.match]). If overload resolution is ambiguous, the program is ill-formed. If no viable functions are found, o is a. Otherwise, o is a call to the selected function with the argument a. If o would be a prvalue, the temporary materialization conversion ([conv.rval]) is applied.
-
e is an lvalue referring to the result of evaluating the (possibly-converted) o.
-
h is an object of typestd::coroutine_handle
referring to the enclosing coroutine.
-
await-ready is the expressione.await_ready(), contextually converted to bool.
-
await-suspend is the expressione.await_suspend(h), which shall be a prvalue of type void, bool, orstd::coroutine_handle for some type Z.
-
await-resume is the expressione.await_resume().
The await-expression has the same type and value category as the await-resume expression.
The await-expression evaluates the (possibly-converted) o expression and the await-ready expression, then:
-
If the result of await-ready is false, the coroutine is considered suspended. Then:
-
If the type of await-suspend is std::coroutine_handle,await-suspend.resume() is evaluated. [Note 1: This resumes the coroutine referred to by the result of await-suspend. Any number of coroutines can be successively resumed in this fashion, eventually returning control flow to the current coroutine caller or resumer ([dcl.fct.def.coroutine]). â end note]
-
Otherwise, if the type of await-suspend is bool,await-suspend is evaluated, and the coroutine is resumed if the result is false.
-
Otherwise, await-suspend is evaluated.
If the evaluation of await-suspend exits via an exception, the exception is caught, the coroutine is resumed, and the exception is immediately rethrown ([except.throw]). Otherwise, control flow returns to the current coroutine caller or resumer ([dcl.fct.def.coroutine]) without exiting any scopes ([stmt.jump]). The point in the coroutine immediately prior to control returning to its caller or resumer is a coroutine suspend point.
-
-
If the result of await-ready is true, or when the coroutine is resumed other than by rethrowing an exception from await-suspend, the await-resume expression is evaluated, and its result is the result of the await-expression.
[Note 2:
With respect to sequencing, an await-expression is indivisible ([intro.execution]).
â end note]
[Example 1: template struct my_future {/* ... */bool await_ready(); void await_suspend(std::coroutine_handle<>); T await_resume();};
template <class Rep, class Period>auto operator co_await(std::chrono::duration<Rep, Period> d) {struct awaiter { std::chrono::system_clock::duration duration; /* ... / awaiter(std::chrono::system_clock::duration d) : duration(d) {}bool await_ready() const { return duration.count() <= 0; }void await_resume() {}void await_suspend(std::coroutine_handle<> h) { / ... */ }}; return awaiter{d};}using namespace std::chrono;
my_future h();
my_future g() { std::cout << "just about to go to sleep...\n"; co_await 10ms; std::cout << "resumed\n"; co_await h();}auto f(int x = co_await h()); // error: await-expression outside of function suspension contextint a[] = { co_await h() }; // error: await-expression outside of function suspension context â end example]