Files
2025-10-25 03:02:53 +03:00

189 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[expr.await]
# 7 Expressions [[expr]](./#expr)
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.await)
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.await)
#### 7.6.2.4 Await [expr.await]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5411)
The co_await expression is used to suspend evaluation of a
coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions")) while awaiting completion of
the computation represented by the operand expression[.](#1.sentence-1)
Suspending the evaluation of a coroutine
transfers control to its caller or resumer[.](#1.sentence-2)
[await-expression:](#nt:await-expression "7.6.2.4Await[expr.await]")
co_await [*cast-expression*](expr.cast#nt:cast-expression "7.6.3Explicit type conversion (cast notation)[expr.cast]")
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5423)
An [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") shall appear only as a potentially-evaluated
expression within the [*compound-statement*](stmt.block#nt:compound-statement "8.4Compound statement or block[stmt.block]") of a[*function-body*](dcl.fct.def.general#nt:function-body "9.6.1General[dcl.fct.def.general]") or [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"),
in either case
outside of a [*handler*](except.pre#nt:handler "14.1Preamble[except.pre]") ([[except.pre]](except.pre "14.1Preamble"))[.](#2.sentence-1)
In a [*declaration-statement*](stmt.dcl#nt:declaration-statement "8.10Declaration statement[stmt.dcl]") or in the[*simple-declaration*](dcl.pre#nt:simple-declaration "9.1Preamble[dcl.pre]") (if any)
of an [*init-statement*](stmt.pre#nt:init-statement "8.1Preamble[stmt.pre]"), an [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") shall appear only in an [*initializer*](dcl.init.general#nt:initializer "9.5.1General[dcl.init.general]") of that[*declaration-statement*](stmt.dcl#nt:declaration-statement "8.10Declaration statement[stmt.dcl]") or [*simple-declaration*](dcl.pre#nt:simple-declaration "9.1Preamble[dcl.pre]")[.](#2.sentence-2)
An [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") shall not appear in a
default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7Default arguments"))[.](#2.sentence-3)
An [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") shall not appear in the initializer of
a block variable with static or thread storage duration[.](#2.sentence-4)
An [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") shall not be
a potentially-evaluated subexpression
of the predicate of a contract assertion ([[basic.contract]](basic.contract "6.11Contract assertions"))[.](#2.sentence-5)
A context within a function where an [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") can appear
is called a [*suspension context*](#def:suspension_context) of the function[.](#2.sentence-6)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5444)
Evaluation of an [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") involves the following
auxiliary types, expressions, and objects:
- [(3.1)](#3.1)
*p* is an lvalue naming the promise
object ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions"))
of the enclosing coroutine and P is the type of that object[.](#3.1.sentence-1)
- [(3.2)](#3.2)
Unless
the [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") was implicitly produced by
a [*yield-expression*](expr.yield#nt:yield-expression "7.6.17Yielding a value[expr.yield]") ([[expr.yield]](expr.yield "7.6.17Yielding a value")),
an initial await expression,
or a final await expression ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions")),
a search is performed for the name await_transform in the scope of P ([[class.member.lookup]](class.member.lookup "6.5.2Member name lookup"))[.](#3.2.sentence-1)
If this search is performed and finds at least one declaration,
then *a* is*p*.await_transform([*cast-expression*](expr.cast#nt:cast-expression "7.6.3Explicit type conversion (cast notation)[expr.cast]"));
otherwise, *a* is the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3Explicit type conversion (cast notation)[expr.cast]")[.](#3.2.sentence-2)
- [(3.3)](#3.3)
*o* is determined by enumerating the applicableoperator co_await functions for an argument*a* ([[over.match.oper]](over.match.oper "12.2.2.3Operators in expressions")), and choosing the best one through
overload resolution ([[over.match]](over.match "12.2Overload resolution"))[.](#3.3.sentence-1)
If overload resolution is ambiguous,
the program is ill-formed[.](#3.3.sentence-2)
If no viable functions are found, *o* is *a*[.](#3.3.sentence-3)
Otherwise, *o* is a call to the selected function
with the argument *a*[.](#3.3.sentence-4)
If *o* would be a prvalue,
the temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion")) is applied[.](#3.3.sentence-5)
- [(3.4)](#3.4)
*e* is an lvalue
referring to the result of evaluating
the (possibly-converted) *o*[.](#3.4.sentence-1)
- [(3.5)](#3.5)
*h* is an object of typestd::coroutine_handle<P> referring to the enclosing coroutine[.](#3.5.sentence-1)
- [(3.6)](#3.6)
*await-ready* is the expression*e*.await_ready(),
contextually converted to bool[.](#3.6.sentence-1)
- [(3.7)](#3.7)
*await-suspend* is the expression*e*.await_suspend(*h*),
which shall be a prvalue of type void, bool, orstd::coroutine_handle<Z> for some type Z[.](#3.7.sentence-1)
- [(3.8)](#3.8)
*await-resume* is the expression*e*.await_resume()[.](#3.8.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5507)
The [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") has the same type and value category
as the *await-resume* expression[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5511)
The [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") evaluates
the (possibly-converted) *o* expression and
the *await-ready* expression, then:
- [(5.1)](#5.1)
If the result of *await-ready* is false,
the coroutine is considered suspended[.](#5.1.sentence-1)
Then:
* [(5.1.1)](#5.1.1)
If the type of *await-suspend* is std::coroutine_handle<Z>,*await-suspend*.resume() is evaluated[.](#5.1.1.sentence-1)
[*Note [1](#note-1)*:
This resumes the coroutine referred to
by the result of *await-suspend*[.](#5.1.1.sentence-2)
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]](dcl.fct.def.coroutine "9.6.4Coroutine definitions"))[.](#5.1.1.sentence-3)
— *end note*]
* [(5.1.2)](#5.1.2)
Otherwise, if the type of *await-suspend* is bool,*await-suspend* is evaluated,
and the coroutine is resumed if the result is false[.](#5.1.2.sentence-1)
* [(5.1.3)](#5.1.3)
Otherwise, *await-suspend* is evaluated[.](#5.1.3.sentence-1)
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]](except.throw "14.2Throwing an exception"))[.](#5.1.sentence-3)
Otherwise, control flow returns
to the current coroutine caller or resumer ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions"))
without exiting any scopes ([[stmt.jump]](stmt.jump "8.8Jump statements"))[.](#5.1.sentence-4)
The point in the coroutine
immediately prior to control returning to its caller or resumer
is a coroutine [*suspend point*](#def:suspend_point "7.6.2.4Await[expr.await]")[.](#5.1.sentence-5)
- [(5.2)](#5.2)
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*](#nt:await-expression "7.6.2.4Await[expr.await]")[.](#5.2.sentence-1)
[*Note [2](#note-2)*:
With respect to sequencing,
an [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") is indivisible ([[intro.execution]](intro.execution "6.10.1Sequential execution"))[.](#5.sentence-2)
— *end note*]
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5565)
[*Example [1](#example-1)*: template <typename T>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<int> h();
my_future<void> 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*](#nt:await-expression "7.6.2.4Await[expr.await]") outside of function suspension contextint a[] = { co_await h() }; // error: [*await-expression*](#nt:await-expression "7.6.2.4Await[expr.await]") outside of function suspension context — *end example*]