793 lines
39 KiB
Markdown
793 lines
39 KiB
Markdown
[dcl.fct.def]
|
||
|
||
# 9 Declarations [[dcl]](./#dcl)
|
||
|
||
## 9.6 Function definitions [dcl.fct.def]
|
||
|
||
### [9.6.1](#general) General [[dcl.fct.def.general]](dcl.fct.def.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6827)
|
||
|
||
Function definitions have the form
|
||
|
||
[function-definition:](#nt:function-definition "9.6.1 General [dcl.fct.def.general]")
|
||
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]")opt [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]") [*virt-specifier-seq*](class.mem.general#nt:virt-specifier-seq "11.4.1 General [class.mem.general]")opt
|
||
[*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]")
|
||
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]")opt [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]") [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")
|
||
[*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]")
|
||
|
||
[function-body:](#nt:function-body "9.6.1 General [dcl.fct.def.general]")
|
||
[*ctor-initializer*](class.base.init#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]")opt [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")
|
||
[*function-try-block*](except.pre#nt:function-try-block "14.1 Preamble [except.pre]")
|
||
= default ;
|
||
[*deleted-function-body*](#nt:deleted-function-body "9.6.1 General [dcl.fct.def.general]")
|
||
|
||
[deleted-function-body:](#nt:deleted-function-body "9.6.1 General [dcl.fct.def.general]")
|
||
= delete ;
|
||
= delete ( [*unevaluated-string*](lex.string.uneval#nt:unevaluated-string "5.13.6 Unevaluated strings [lex.string.uneval]") ) ;
|
||
|
||
Any informal reference to the body of a function should be interpreted as a reference to
|
||
the non-terminal [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]"),
|
||
including, for a constructor,
|
||
default member initializers or default initialization
|
||
used to initialize
|
||
a base or member subobject in the absence of
|
||
a [*mem-initializer-id*](class.base.init#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") ([[class.base.init]](class.base.init "11.9.3 Initializing bases and members"))[.](#general-1.sentence-2)
|
||
|
||
The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*function-definition*](#nt:function-definition "9.6.1 General [dcl.fct.def.general]") appertains to the function[.](#general-1.sentence-3)
|
||
|
||
A [*function-definition*](#nt:function-definition "9.6.1 General [dcl.fct.def.general]") with a [*virt-specifier-seq*](class.mem.general#nt:virt-specifier-seq "11.4.1 General [class.mem.general]") shall be a [*member-declaration*](class.mem.general#nt:member-declaration "11.4.1 General [class.mem.general]") ([[class.mem]](class.mem "11.4 Class members"))[.](#general-1.sentence-4)
|
||
|
||
A [*function-definition*](#nt:function-definition "9.6.1 General [dcl.fct.def.general]") with a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") shall define a templated function[.](#general-1.sentence-5)
|
||
|
||
[2](#general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6868)
|
||
|
||
In a [*function-definition*](#nt:function-definition "9.6.1 General [dcl.fct.def.general]"),
|
||
either void [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]") ; or [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]") ; shall be a well-formed function declaration
|
||
as described in [[dcl.fct]](dcl.fct "9.3.4.6 Functions")[.](#general-2.sentence-1)
|
||
|
||
A function shall be defined only in namespace or class scope[.](#general-2.sentence-2)
|
||
|
||
The type of a parameter or the return type for a function
|
||
definition shall not be
|
||
a (possibly cv-qualified) class type that is
|
||
incomplete or abstract within the function body
|
||
unless the function is deleted ([[dcl.fct.def.delete]](#delete "9.6.3 Deleted definitions"))[.](#general-2.sentence-3)
|
||
|
||
[3](#general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6881)
|
||
|
||
[*Example [1](#general-example-1)*:
|
||
|
||
A simple example of a complete function definition isint max(int a, int b, int c) {int m = (a > b) ? a : b; return (m > c) ? m : c;}
|
||
|
||
Hereint is the[*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]");max(inta,intb,intc) is the[*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]");{ /* ... */ } is the[*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]")[.](#general-3.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[4](#general-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6908)
|
||
|
||
A[*ctor-initializer*](class.base.init#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]") is used only in a constructor; see [[class.ctor]](class.ctor "11.4.5 Constructors") and [[class.init]](class.init "11.9 Initialization")[.](#general-4.sentence-1)
|
||
|
||
[5](#general-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6916)
|
||
|
||
[*Note [1](#general-note-1)*:
|
||
|
||
A [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") affects the type of this in the body of a member function; see [[expr.prim.this]](expr.prim.this "7.5.3 This")[.](#general-5.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[6](#general-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6922)
|
||
|
||
[*Note [2](#general-note-2)*:
|
||
|
||
Unused parameters need not be named[.](#general-6.sentence-1)
|
||
|
||
For example,
|
||
|
||
void print(int a, int) { std::printf("a = %d\n",a);} â *end note*]
|
||
|
||
[7](#general-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6934)
|
||
|
||
A [*function-local predefined variable*](#def:variable,function-local_predefined "9.6.1 General [dcl.fct.def.general]") is a variable with static
|
||
storage duration that is implicitly defined in a function parameter scope[.](#general-7.sentence-1)
|
||
|
||
[8](#general-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6938)
|
||
|
||
The function-local predefined variable __func__ is
|
||
defined as if a definition of the formstatic const char __func__[] = "*function-name*"; had been provided, where *function-name* is an implementation-defined string[.](#general-8.sentence-1)
|
||
|
||
It is unspecified whether such a variable has an address
|
||
distinct from that of any other object in the program[.](#general-8.sentence-2)[81](#footnote-81 "Implementations are permitted to provide additional predefined variables with names that are reserved to the implementation ([lex.name]). If a predefined variable is not odr-used ([term.odr.use]), its string value need not be present in the program image.")
|
||
|
||
[*Example [2](#general-example-2)*: struct S { S() : s(__func__) { } // OKconst char* s;};void f(const char* s = __func__); // error: __func__ is undeclared â *end example*]
|
||
|
||
[81)](#footnote-81)[81)](#footnoteref-81)
|
||
|
||
Implementations are
|
||
permitted to provide additional predefined variables with names that are reserved to the
|
||
implementation ([[lex.name]](lex.name "5.11 Identifiers"))[.](#footnote-81.sentence-1)
|
||
|
||
If a predefined variable is not
|
||
odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")), its string value need not be present in the program image[.](#footnote-81.sentence-2)
|
||
|
||
### [9.6.2](#default) Explicitly-defaulted functions [[dcl.fct.def.default]](dcl.fct.def.default)
|
||
|
||
[1](#default-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6967)
|
||
|
||
A function definition whose[*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]") is of the form= default ; is called an [*explicitly-defaulted*](#def:definition,function,explicitly-defaulted "9.6.2 Explicitly-defaulted functions [dcl.fct.def.default]") definition[.](#default-1.sentence-1)
|
||
|
||
A function that is explicitly defaulted shall
|
||
|
||
- [(1.1)](#default-1.1)
|
||
|
||
be a special member function ([[special]](special "11.4.4 Special member functions")) or
|
||
a comparison operator function ([[over.binary]](over.binary "12.4.3 Binary operators"), [[class.compare.default]](class.compare.default "11.10.1 Defaulted comparison operator functions")), and
|
||
|
||
- [(1.2)](#default-1.2)
|
||
|
||
not have default arguments ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#default-1.sentence-2)
|
||
|
||
[2](#default-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6980)
|
||
|
||
An explicitly defaulted special member function F1 is allowed to differ from
|
||
the corresponding special member function F2 that would have been implicitly declared, as follows:
|
||
|
||
- [(2.1)](#default-2.1)
|
||
|
||
F1 and F2 may have differing [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]")*s*;
|
||
|
||
- [(2.2)](#default-2.2)
|
||
|
||
if F2 has an implicit object parameter of
|
||
type âreference to Câ, F1 may be an explicit object member function whose
|
||
explicit object parameter is of (possibly different) type âreference to Câ,
|
||
in which case the type of F1 would differ from the type of F2 in that the type of F1 has an additional parameter;
|
||
|
||
- [(2.3)](#default-2.3)
|
||
|
||
F1 and F2 may have differing exception specifications; and
|
||
|
||
- [(2.4)](#default-2.4)
|
||
|
||
if F2 has a non-object parameter of type const C&,
|
||
the corresponding non-object parameter of F1 may be of
|
||
type C&[.](#default-2.sentence-1)
|
||
|
||
If the type of F1 differs from the type of F2 in a way
|
||
other than as allowed by the preceding rules, then:
|
||
|
||
- [(2.5)](#default-2.5)
|
||
|
||
if F1 is an assignment operator, and
|
||
the return type of F1 differs from
|
||
the return type of F2 or F1's non-object parameter type is not a reference,
|
||
the program is ill-formed;
|
||
|
||
- [(2.6)](#default-2.6)
|
||
|
||
otherwise, if F1 is explicitly defaulted on its first declaration,
|
||
it is defined as deleted;
|
||
|
||
- [(2.7)](#default-2.7)
|
||
|
||
otherwise, the program is ill-formed[.](#default-2.sentence-2)
|
||
|
||
[3](#default-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7018)
|
||
|
||
A function explicitly defaulted on its first declaration
|
||
is implicitly inline ([[dcl.inline]](dcl.inline "9.2.8 The inline specifier")),
|
||
and is implicitly constexpr ([[dcl.constexpr]](dcl.constexpr "9.2.6 The constexpr and consteval specifiers"))
|
||
if it is constexpr-suitable[.](#default-3.sentence-1)
|
||
|
||
[*Note [1](#default-note-1)*:
|
||
|
||
Other defaulted functions are not implicitly constexpr[.](#default-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[4](#default-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7027)
|
||
|
||
[*Example [1](#default-example-1)*: struct S { S(int a = 0) = default; // error: default argumentvoid operator=(const S&) = default; // error: non-matching return type~S() noexcept(false) = default; // OK, despite mismatched exception specificationprivate:int i;
|
||
S(S&); // OK, private copy constructor};
|
||
S::S(S&) = default; // OK, defines copy constructorstruct T { T();
|
||
T(T &&) noexcept(false);};struct U { T t;
|
||
U();
|
||
U(U &&) noexcept = default;};
|
||
U u1;
|
||
U u2 = static_cast<U&&>(u1); // OK, calls std::terminate if T::T(T&&) throws â *end example*]
|
||
|
||
[5](#default-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7054)
|
||
|
||
Explicitly-defaulted functions and implicitly-declared functions are collectively
|
||
called [*defaulted*](#def:defaulted "9.6.2 Explicitly-defaulted functions [dcl.fct.def.default]") functions, and the implementation
|
||
shall provide implicit definitions
|
||
for them ([[class.ctor]](class.ctor "11.4.5 Constructors"), [[class.dtor]](class.dtor "11.4.7 Destructors"), [[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors"), [[class.copy.assign]](class.copy.assign "11.4.6 Copy/move assignment operator")) as described below,
|
||
including possibly defining them as deleted[.](#default-5.sentence-1)
|
||
|
||
A defaulted prospective destructor ([[class.dtor]](class.dtor "11.4.7 Destructors"))
|
||
that is not a destructor is defined as deleted[.](#default-5.sentence-2)
|
||
|
||
A defaulted special member function
|
||
that is neither a prospective destructor nor
|
||
an eligible special member function ([[special]](special "11.4.4 Special member functions"))
|
||
is defined as deleted[.](#default-5.sentence-3)
|
||
|
||
A function is[*user-provided*](#def:user-provided "9.6.2 Explicitly-defaulted functions [dcl.fct.def.default]") if it is user-declared and not explicitly
|
||
defaulted or deleted on its first declaration[.](#default-5.sentence-4)
|
||
|
||
A user-provided explicitly-defaulted function
|
||
(i.e., explicitly defaulted after its first declaration)
|
||
is implicitly defined at the point where it is explicitly defaulted; if such a function is implicitly
|
||
defined as deleted, the program is ill-formed[.](#default-5.sentence-5)
|
||
|
||
[*Note [2](#default-note-2)*:
|
||
|
||
Declaring a function as defaulted after its first declaration
|
||
can provide efficient execution and concise definition
|
||
while enabling a stable binary interface to an evolving code base[.](#default-5.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
A non-user-provided defaulted function
|
||
(i.e., implicitly declared or explicitly defaulted in the class)
|
||
that is not defined as deleted is implicitly defined when it is odr-used ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))
|
||
or needed for constant evaluation ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#default-5.sentence-7)
|
||
|
||
[*Note [3](#default-note-3)*:
|
||
|
||
The implicit definition of a non-user-provided defaulted function
|
||
does not bind any names[.](#default-5.sentence-8)
|
||
|
||
â *end note*]
|
||
|
||
[6](#default-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7086)
|
||
|
||
[*Example [2](#default-example-2)*: struct trivial { trivial() = default;
|
||
trivial(const trivial&) = default;
|
||
trivial(trivial&&) = default;
|
||
trivial& operator=(const trivial&) = default;
|
||
trivial& operator=(trivial&&) = default; ~trivial() = default;};
|
||
|
||
struct nontrivial1 { nontrivial1();};
|
||
nontrivial1::nontrivial1() = default; // not first declaration â *end example*]
|
||
|
||
### [9.6.3](#delete) Deleted definitions [[dcl.fct.def.delete]](dcl.fct.def.delete)
|
||
|
||
[1](#delete-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7108)
|
||
|
||
A [*deleted definition*](#def:definition,deleted "9.6.3 Deleted definitions [dcl.fct.def.delete]") of a function is a function definition
|
||
whose [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]") is a [*deleted-function-body*](#nt:deleted-function-body "9.6.1 General [dcl.fct.def.general]") or an explicitly-defaulted definition of the function where the function is
|
||
defined as deleted[.](#delete-1.sentence-1)
|
||
|
||
A [*deleted function*](#def:function,deleted "9.6.3 Deleted definitions [dcl.fct.def.delete]") is
|
||
a function with a
|
||
deleted definition or a function that is implicitly defined as deleted[.](#delete-1.sentence-2)
|
||
|
||
[2](#delete-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7117)
|
||
|
||
A construct that designates a deleted function implicitly or explicitly,
|
||
other than to declare it or to appear as the operand of
|
||
a [*reflect-expression*](expr.reflect#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") ([[expr.reflect]](expr.reflect "7.6.2.10 The reflection operator")),
|
||
is ill-formed[.](#delete-2.sentence-1)
|
||
|
||
*Recommended practice*: The resulting diagnostic message should include
|
||
the text of the [*unevaluated-string*](lex.string.uneval#nt:unevaluated-string "5.13.6 Unevaluated strings [lex.string.uneval]"),
|
||
if one is supplied[.](#delete-2.sentence-2)
|
||
|
||
[*Note [1](#delete-note-1)*:
|
||
|
||
This includes calling the function
|
||
implicitly or explicitly and forming a pointer or pointer-to-member to the
|
||
function[.](#delete-2.sentence-3)
|
||
|
||
It applies even for references in expressions that are not
|
||
potentially-evaluated[.](#delete-2.sentence-4)
|
||
|
||
For an overload set, only the
|
||
function selected by overload resolution is referenced[.](#delete-2.sentence-5)
|
||
|
||
The implicit
|
||
odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) of a virtual function does not, by itself,
|
||
constitute a reference[.](#delete-2.sentence-6)
|
||
|
||
The [*unevaluated-string*](lex.string.uneval#nt:unevaluated-string "5.13.6 Unevaluated strings [lex.string.uneval]"), if present,
|
||
can be used to explain the rationale for deletion and/or
|
||
to suggest an alternative[.](#delete-2.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[3](#delete-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7141)
|
||
|
||
[*Example [1](#delete-example-1)*:
|
||
|
||
One can prevent default initialization and
|
||
initialization by non-doubles withstruct onlydouble { onlydouble() = delete; // OK, but redundanttemplate<class T> onlydouble(T) = delete;
|
||
onlydouble(double);};
|
||
|
||
â *end example*]
|
||
|
||
[*Example [2](#delete-example-2)*:
|
||
|
||
One can prevent use of a
|
||
class in certain [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")*s* by using deleted definitions
|
||
of a user-declared operator new for that class[.](#delete-3.sentence-2)
|
||
|
||
struct sometype {void* operator new(std::size_t) = delete; void* operator new[](std::size_t) = delete;};
|
||
sometype* p = new sometype; // error: deleted class operator new sometype* q = new sometype[3]; // error: deleted class operator new[] â *end example*]
|
||
|
||
[*Example [3](#delete-example-3)*:
|
||
|
||
One can make a class uncopyable, i.e., move-only, by using deleted
|
||
definitions of the copy constructor and copy assignment operator, and then
|
||
providing defaulted definitions of the move constructor and move assignment operator[.](#delete-3.sentence-3)
|
||
|
||
struct moveonly { moveonly() = default;
|
||
moveonly(const moveonly&) = delete;
|
||
moveonly(moveonly&&) = default;
|
||
moveonly& operator=(const moveonly&) = delete;
|
||
moveonly& operator=(moveonly&&) = default; ~moveonly() = default;};
|
||
moveonly* p;
|
||
moveonly q(*p); // error: deleted copy constructor â *end example*]
|
||
|
||
[4](#delete-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7187)
|
||
|
||
A deleted function is implicitly an inline function ([[dcl.inline]](dcl.inline "9.2.8 The inline specifier"))[.](#delete-4.sentence-1)
|
||
|
||
[*Note [2](#delete-note-2)*:
|
||
|
||
The
|
||
one-definition rule ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")) applies to deleted definitions[.](#delete-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
A deleted definition of a function shall be the first declaration of the function or,
|
||
for an explicit specialization of a function template, the first declaration of that
|
||
specialization[.](#delete-4.sentence-3)
|
||
|
||
An implicitly declared allocation or deallocation function ([[basic.stc.dynamic]](basic.stc.dynamic "6.8.6.5 Dynamic storage duration"))
|
||
shall not be defined as deleted[.](#delete-4.sentence-4)
|
||
|
||
[*Example [4](#delete-example-4)*: struct sometype { sometype();};
|
||
sometype::sometype() = delete; // error: not first declaration â *end example*]
|
||
|
||
### [9.6.4](#coroutine) Coroutine definitions [[dcl.fct.def.coroutine]](dcl.fct.def.coroutine)
|
||
|
||
[1](#coroutine-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7211)
|
||
|
||
A function is a [*coroutine*](#def:coroutine "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") if its [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]") encloses a[*coroutine-return-statement*](stmt.return.coroutine#nt:coroutine-return-statement "8.8.5 The co_return statement [stmt.return.coroutine]") ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_return statement")),
|
||
an [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") ([[expr.await]](expr.await "7.6.2.4 Await")),
|
||
or a [*yield-expression*](expr.yield#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") ([[expr.yield]](expr.yield "7.6.17 Yielding a value"))[.](#coroutine-1.sentence-1)
|
||
|
||
The [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of the coroutine shall not
|
||
terminate with an ellipsis that is not part of
|
||
a [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")[.](#coroutine-1.sentence-2)
|
||
|
||
[2](#coroutine-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7220)
|
||
|
||
[*Example [1](#coroutine-example-1)*: task<int> f();
|
||
|
||
task<void> g1() {int i = co_await f();
|
||
std::cout << "f() => " << i << std::endl;}template <typename... Args> task<void> g2(Args&&...) { // OK, ellipsis is a pack expansionint i = co_await f();
|
||
std::cout << "f() => " << i << std::endl;} task<void> g3(int a, ...) { // error: variable parameter list not allowedint i = co_await f();
|
||
std::cout << "f() => " << i << std::endl;} â *end example*]
|
||
|
||
[3](#coroutine-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7243)
|
||
|
||
The [*promise type*](#def:coroutine,promise_type "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") of a coroutine isstd::coroutine_traits<R, P1, …, Pn>::promise_type,
|
||
whereR is the return type of the function, andP1â¦Pn is the sequence of types of the non-object function parameters,
|
||
preceded by the type of the object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))
|
||
if the coroutine is a non-static member function[.](#coroutine-3.sentence-1)
|
||
|
||
The promise type shall be a class type[.](#coroutine-3.sentence-2)
|
||
|
||
[4](#coroutine-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7254)
|
||
|
||
In the following, pi is an lvalue of type Pi,
|
||
wherep1 denotes the object parameter andpi+1 denotes the ith non-object function parameter
|
||
for an implicit object member function, andpi denotes
|
||
the ith function parameter otherwise[.](#coroutine-4.sentence-1)
|
||
|
||
For an implicit object member function,q1 is an lvalue that denotes *this;
|
||
any other qi is an lvalue
|
||
that denotes the parameter copy corresponding to pi,
|
||
as described below[.](#coroutine-4.sentence-2)
|
||
|
||
[5](#coroutine-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7268)
|
||
|
||
A coroutine behaves as if
|
||
the top-level cv-qualifiers in all[*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")*s* in the declarator
|
||
of its [*function-definition*](#nt:function-definition "9.6.1 General [dcl.fct.def.general]") were removed and
|
||
its [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]") were replaced by
|
||
the following [*replacement body*](#def:body,replacement "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"):
|
||
|
||
{
|
||
*promise-type* *promise* *promise-constructor-arguments* ;
|
||
try {
|
||
co_await *promise*.initial_suspend() ;
|
||
[*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]")
|
||
} catch ( ... ) {
|
||
if (!*initial-await-resume-called*)
|
||
throw ;
|
||
*promise*.unhandled_exception() ;
|
||
}
|
||
*final-suspend* :
|
||
co_await *promise*.final_suspend() ;
|
||
}
|
||
|
||
where
|
||
|
||
- [(5.1)](#coroutine-5.1)
|
||
|
||
the [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") containing
|
||
the call to initial_suspend is the [*initial await expression*](#def:await_expression,initial "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"), and
|
||
|
||
- [(5.2)](#coroutine-5.2)
|
||
|
||
the [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") containing
|
||
the call to final_suspend is the [*final await expression*](#def:await_expression,final "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"), and
|
||
|
||
- [(5.3)](#coroutine-5.3)
|
||
|
||
*initial-await-resume-called* is initially false and is set to true immediately before the evaluation
|
||
of the *await-resume* expression ([[expr.await]](expr.await "7.6.2.4 Await"))
|
||
of the initial await expression, and
|
||
|
||
- [(5.4)](#coroutine-5.4)
|
||
|
||
*promise-type* denotes the promise type, and
|
||
|
||
- [(5.5)](#coroutine-5.5)
|
||
|
||
the object denoted by the exposition-only name *promise* is the [*promise object*](#def:promise_object "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") of the coroutine, and
|
||
|
||
- [(5.6)](#coroutine-5.6)
|
||
|
||
the label denoted by the name *final-suspend* is defined for exposition only ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_return statement")), and
|
||
|
||
- [(5.7)](#coroutine-5.7)
|
||
|
||
*promise-constructor-arguments* is determined as follows:
|
||
overload resolution is performed on a promise constructor call created by
|
||
assembling an argument list q1â¦qn[.](#coroutine-5.7.sentence-1)
|
||
If a viable
|
||
constructor is found ([[over.match.viable]](over.match.viable "12.2.3 Viable functions")), then*promise-constructor-arguments* is(q1, …, qn), otherwise*promise-constructor-arguments* is empty, and
|
||
|
||
- [(5.8)](#coroutine-5.8)
|
||
|
||
a coroutine is suspended at the [*initial suspend point*](#def:suspend_point,initial "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") if
|
||
it is suspended at the initial await expression, and
|
||
|
||
- [(5.9)](#coroutine-5.9)
|
||
|
||
a coroutine is suspended at a [*final suspend point*](#def:suspend_point,final "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") if
|
||
it is suspended
|
||
* [(5.9.1)](#coroutine-5.9.1)
|
||
|
||
at a final await expression or
|
||
|
||
* [(5.9.2)](#coroutine-5.9.2)
|
||
|
||
due to an exception exiting from unhandled_exception()[.](#coroutine-5.9.sentence-1)
|
||
|
||
[6](#coroutine-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7340)
|
||
|
||
[*Note [1](#coroutine-note-1)*:
|
||
|
||
An odr-use of a non-reference parameter
|
||
in a postcondition assertion
|
||
of a coroutine is ill-formed ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))[.](#coroutine-6.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[7](#coroutine-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7347)
|
||
|
||
If searches for the names return_void and return_value in the scope of the promise type each find any declarations,
|
||
the program is ill-formed[.](#coroutine-7.sentence-1)
|
||
|
||
[*Note [2](#coroutine-note-2)*:
|
||
|
||
If return_void is found, flowing off
|
||
the end of a coroutine is equivalent to a co_return with no operand[.](#coroutine-7.sentence-2)
|
||
|
||
Otherwise, flowing off the end of a coroutine
|
||
results in undefined behavior ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_return statement"))[.](#coroutine-7.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[8](#coroutine-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7358)
|
||
|
||
The expression *promise*.get_return_object() is used
|
||
to initialize
|
||
the returned reference or prvalue result object of a call to a coroutine[.](#coroutine-8.sentence-1)
|
||
|
||
The call to get_return_object is sequenced before
|
||
the call to initial_suspend and is invoked at most once[.](#coroutine-8.sentence-2)
|
||
|
||
[9](#coroutine-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7367)
|
||
|
||
A suspended coroutine can be resumed to continue execution by invoking
|
||
a resumption member function ([[coroutine.handle.resumption]](coroutine.handle.resumption "17.13.4.6 Resumption"))
|
||
of a coroutine handle ([[coroutine.handle]](coroutine.handle "17.13.4 Class template coroutine_handle"))
|
||
that refers to the coroutine[.](#coroutine-9.sentence-1)
|
||
|
||
The evaluation that invoked a resumption member function is
|
||
called the [*resumer*](#def:coroutine,resumer "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]")[.](#coroutine-9.sentence-2)
|
||
|
||
Invoking a resumption member function for a coroutine
|
||
that is not suspended results in undefined behavior[.](#coroutine-9.sentence-3)
|
||
|
||
[10](#coroutine-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7377)
|
||
|
||
An implementation may need to allocate additional storage for a coroutine[.](#coroutine-10.sentence-1)
|
||
|
||
This storage is known as the [*coroutine state*](#def:coroutine_state "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") and is obtained by calling
|
||
a non-array allocation function ([[basic.stc.dynamic.allocation]](basic.stc.dynamic.allocation "6.8.6.5.2 Allocation functions"))
|
||
as part of the replacement body[.](#coroutine-10.sentence-2)
|
||
|
||
The allocation function's name is looked up by searching for it in the scope of the promise type[.](#coroutine-10.sentence-3)
|
||
|
||
- [(10.1)](#coroutine-10.1)
|
||
|
||
If the search finds any declarations,
|
||
overload resolution is performed on a function call created by assembling an
|
||
argument list[.](#coroutine-10.1.sentence-1)
|
||
The first argument is the amount of space requested, and
|
||
is a prvalue of type std::size_t[.](#coroutine-10.1.sentence-2)
|
||
The lvalues p1â¦pn with their original types (including cv-qualifiers)
|
||
are the successive arguments[.](#coroutine-10.1.sentence-3)
|
||
If no viable function is found ([[over.match.viable]](over.match.viable "12.2.3 Viable functions")),
|
||
overload resolution is performed again
|
||
on a function call created by passing just
|
||
the amount of space required as a prvalue of type std::size_t[.](#coroutine-10.1.sentence-4)
|
||
|
||
- [(10.2)](#coroutine-10.2)
|
||
|
||
If the search finds no declarations, a search is performed in the global scope[.](#coroutine-10.2.sentence-1)
|
||
Overload resolution is performed on a function call created by
|
||
passing the amount of space required as a prvalue of type std::size_t[.](#coroutine-10.2.sentence-2)
|
||
|
||
[11](#coroutine-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7402)
|
||
|
||
If a search for the name get_return_object_on_allocation_failure in the scope of the promise type ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup")) finds
|
||
any declarations, then the result
|
||
of a call to an allocation function used to obtain storage for the coroutine
|
||
state is assumed to return nullptr if it fails to obtain storage,
|
||
and if a global allocation function is selected,
|
||
the ::operator new(size_t, nothrow_t) form is used[.](#coroutine-11.sentence-1)
|
||
|
||
The allocation function used in this case shall have a non-throwing[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")[.](#coroutine-11.sentence-2)
|
||
|
||
If the allocation function returns nullptr, the coroutine transfers
|
||
control to the caller of the coroutine and the return value is obtained by a
|
||
call to T::get_return_object_on_allocation_failure(), where T is the promise type[.](#coroutine-11.sentence-3)
|
||
|
||
[*Example [2](#coroutine-example-2)*: #include <iostream>#include <coroutine>// ::operator new(size_t, nothrow_t) will be used if allocation is neededstruct generator {struct promise_type; using handle = std::coroutine_handle<promise_type>; struct promise_type {int current_value; static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }auto get_return_object() { return generator{handle::from_promise(*this)}; }auto initial_suspend() { return std::suspend_always{}; }auto final_suspend() noexcept { return std::suspend_always{}; }void unhandled_exception() { std::terminate(); }void return_void() {}auto yield_value(int value) { current_value = value; return std::suspend_always{}; }}; bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }int current_value() { return coro.promise().current_value; } generator(generator const&) = delete;
|
||
generator(generator && rhs) : coro(rhs.coro) { rhs.coro = nullptr; }~generator() { if (coro) coro.destroy(); }private: generator(handle h) : coro(h) {} handle coro;};
|
||
generator f() { co_yield 1; co_yield 2; }int main() {auto g = f(); while (g.move_next()) std::cout << g.current_value() << std::endl;} â *end example*]
|
||
|
||
[12](#coroutine-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7456)
|
||
|
||
The coroutine state is destroyed when control flows off the end of the
|
||
coroutine or the destroy member
|
||
function ([[coroutine.handle.resumption]](coroutine.handle.resumption "17.13.4.6 Resumption"))
|
||
of a coroutine handle ([[coroutine.handle]](coroutine.handle "17.13.4 Class template coroutine_handle"))
|
||
that refers to the coroutine
|
||
is invoked[.](#coroutine-12.sentence-1)
|
||
|
||
In the latter case,
|
||
control in the coroutine is considered
|
||
to be transferred out of the function ([[stmt.dcl]](stmt.dcl "8.10 Declaration statement"))[.](#coroutine-12.sentence-2)
|
||
|
||
The storage for the coroutine state is released by calling a
|
||
non-array deallocation function ([[basic.stc.dynamic.deallocation]](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions"))[.](#coroutine-12.sentence-3)
|
||
|
||
If destroy is called for a coroutine that is not suspended, the
|
||
program has undefined behavior[.](#coroutine-12.sentence-4)
|
||
|
||
[13](#coroutine-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7471)
|
||
|
||
The deallocation function's name is looked up by searching for it in the scope of the promise type[.](#coroutine-13.sentence-1)
|
||
|
||
If nothing is found, a search is performed in the
|
||
global scope[.](#coroutine-13.sentence-2)
|
||
|
||
If both a usual deallocation
|
||
function with only a pointer parameter and a usual deallocation function with
|
||
both a pointer parameter and a size parameter are found, then the selected deallocation
|
||
function shall be the one with two parameters[.](#coroutine-13.sentence-3)
|
||
|
||
Otherwise, the selected
|
||
deallocation function shall be the function with one parameter[.](#coroutine-13.sentence-4)
|
||
|
||
If no usual
|
||
deallocation function is found, the program is ill-formed[.](#coroutine-13.sentence-5)
|
||
|
||
The selected deallocation function shall be called with the address of the
|
||
block of storage to be reclaimed as its first argument[.](#coroutine-13.sentence-6)
|
||
|
||
If a deallocation
|
||
function with a parameter of type std::size_t is used, the size of
|
||
the block is passed as the corresponding argument[.](#coroutine-13.sentence-7)
|
||
|
||
[14](#coroutine-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7485)
|
||
|
||
When a coroutine is invoked,
|
||
a copy is created for each coroutine parameter
|
||
at the beginning of the replacement body[.](#coroutine-14.sentence-1)
|
||
|
||
For a parameter
|
||
whose original declaration specified the type cv T,
|
||
|
||
- [(14.1)](#coroutine-14.1)
|
||
|
||
if T is a reference type,
|
||
the copy is a reference of typecv T bound to the same object as a parameter;
|
||
|
||
- [(14.2)](#coroutine-14.2)
|
||
|
||
otherwise, the copy is a variable
|
||
of type cv T with automatic storage duration that is direct-initialized
|
||
from an xvalue of type T referring to the parameter[.](#coroutine-14.sentence-2)
|
||
|
||
[*Note [3](#coroutine-note-3)*:
|
||
|
||
An identifier in the [*function-body*](#nt:function-body "9.6.1 General [dcl.fct.def.general]") that names one of these parameters
|
||
refers to the created copy,
|
||
not the original parameter ([[expr.prim.id.unqual]](expr.prim.id.unqual "7.5.5.2 Unqualified names"))[.](#coroutine-14.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
The initialization and destruction of each parameter copy occurs in the
|
||
context of the called coroutine[.](#coroutine-14.sentence-4)
|
||
|
||
Initializations of parameter copies are sequenced before the call to the
|
||
coroutine promise constructor and indeterminately sequenced with respect to
|
||
each other[.](#coroutine-14.sentence-5)
|
||
|
||
The lifetime of parameter copies ends immediately after the lifetime of the
|
||
coroutine promise object ends[.](#coroutine-14.sentence-6)
|
||
|
||
[*Note [4](#coroutine-note-4)*:
|
||
|
||
If a coroutine has a parameter passed by reference, resuming the coroutine
|
||
after the lifetime of the entity referred to by that parameter has ended is
|
||
likely to result in undefined behavior[.](#coroutine-14.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[15](#coroutine-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7523)
|
||
|
||
If the evaluation of the expression*promise*.unhandled_exception() exits via an exception,
|
||
the coroutine is considered suspended at the final suspend point
|
||
and the exception propagates to the caller or resumer[.](#coroutine-15.sentence-1)
|
||
|
||
[16](#coroutine-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7529)
|
||
|
||
The expression co_await *promise*.final_suspend() shall not be potentially-throwing ([[except.spec]](except.spec "14.5 Exception specifications"))[.](#coroutine-16.sentence-1)
|
||
|
||
### [9.6.5](#replace) Replaceable function definitions [[dcl.fct.def.replace]](dcl.fct.def.replace)
|
||
|
||
[1](#replace-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7538)
|
||
|
||
Certain functions
|
||
for which a definition is supplied by the implementation
|
||
are [*replaceable*](#def:function,replaceable "9.6.5 Replaceable function definitions [dcl.fct.def.replace]")[.](#replace-1.sentence-1)
|
||
|
||
A C++ program may
|
||
provide a definition with the signature of a replaceable function,
|
||
called a [*replacement function*](#def:function,replacement "9.6.5 Replaceable function definitions [dcl.fct.def.replace]")[.](#replace-1.sentence-2)
|
||
|
||
The replacement function
|
||
is used instead of the default version
|
||
supplied by the implementation[.](#replace-1.sentence-3)
|
||
|
||
Such replacement occurs
|
||
prior to program startup ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"), [[basic.start]](basic.start "6.10.3 Start and termination"))[.](#replace-1.sentence-4)
|
||
|
||
A declaration of the replacement function
|
||
|
||
- [(1.1)](#replace-1.1)
|
||
|
||
shall not be inline,
|
||
|
||
- [(1.2)](#replace-1.2)
|
||
|
||
shall be attached to the global module,
|
||
|
||
- [(1.3)](#replace-1.3)
|
||
|
||
shall have C++ language linkage,
|
||
|
||
- [(1.4)](#replace-1.4)
|
||
|
||
shall have the same return type as the replaceable function, and
|
||
|
||
- [(1.5)](#replace-1.5)
|
||
|
||
if the function is declared in a standard library header,
|
||
shall be such that it would be valid as a redeclaration
|
||
of the declaration in that header;
|
||
|
||
no diagnostic is required[.](#replace-1.sentence-5)
|
||
|
||
[*Note [1](#replace-note-1)*:
|
||
|
||
The one-definition rule ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))
|
||
applies to the definitions of a replaceable function
|
||
provided by the program[.](#replace-1.sentence-6)
|
||
|
||
The implementation-supplied function definition
|
||
is an otherwise-unnamed function with no linkage[.](#replace-1.sentence-7)
|
||
|
||
â *end note*]
|