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

413 lines
27 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.

[dcl.spec.auto]
# 9 Declarations [[dcl]](./#dcl)
## 9.2 Specifiers [[dcl.spec]](dcl.spec#auto)
### 9.2.9 Type specifiers [[dcl.type]](dcl.type#dcl.spec.auto)
#### 9.2.9.7 Placeholder type specifiers [dcl.spec.auto]
#### [9.2.9.7.1](#general) General [[dcl.spec.auto.general]](dcl.spec.auto.general)
[placeholder-type-specifier:](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]")
[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto
[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt decltype ( auto )
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1825)
A [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") designates a placeholder type that will be replaced later,
typically by deduction
from an initializer[.](#general-1.sentence-1)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1831)
The type of a [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6Functions[dcl.fct]") of a
- [(2.1)](#general-2.1)
function declaration ([[dcl.fct]](dcl.fct "9.3.4.6Functions")),
- [(2.2)](#general-2.2)
[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda expressions")), or
- [(2.3)](#general-2.3)
[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") ([[temp.param]](temp.param "13.2Template parameters"))
can be declared using
a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto[.](#general-2.sentence-1)
The placeholder type shall appear
as one of the [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such
a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]") (see below);
the placeholder type
is a [*generic parameter type placeholder*](#def:generic_parameter_type_placeholder "9.2.9.7.1General[dcl.spec.auto.general]") of the
function declaration,[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"), or[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]"), respectively[.](#general-2.sentence-2)
[*Note [1](#general-note-1)*:
Having a generic parameter type placeholder
signifies that the function is
an abbreviated function template ([[dcl.fct]](dcl.fct "9.3.4.6Functions")) or
the lambda is a generic lambda ([[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda expressions"))[.](#general-2.sentence-3)
— *end note*]
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1861)
A placeholder type can appear in
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") for a function declarator
that includes a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") ([[dcl.fct]](dcl.fct "9.3.4.6Functions"))[.](#general-3.sentence-1)
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1866)
A placeholder type can appear in
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") in the declared return type of a function declarator that declares a function;
the return type of the function is
deduced from non-discarded return statements, if any, in the body
of the function ([[stmt.if]](stmt.if "8.5.2The if statement"))[.](#general-4.sentence-1)
[5](#general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1874)
The type of a variable declared using a placeholder type is
deduced from its initializer[.](#general-5.sentence-1)
This use is allowed
in an initializing declaration ([[dcl.init]](dcl.init "9.5Initializers")) of a variable[.](#general-5.sentence-2)
The placeholder type shall appear as one of the[*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or as one of the[*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]");
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") shall be followed by one or more[*declarator*](dcl.decl.general#nt:declarator "9.3.1General[dcl.decl.general]")*s*,
each of which shall
be followed by a non-empty[*initializer*](dcl.init.general#nt:initializer "9.5.1General[dcl.init.general]")[.](#general-5.sentence-3)
[*Example [1](#general-example-1)*: auto x = 5; // OK, x has type intconst auto *v = &x, u = 6; // OK, v has type const int*, u has type const intstatic auto y = 0.0; // OK, y has type doubleauto int r; // error: auto is not a [*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]")auto f() -> int; // OK, f returns intauto g() { return 0.0; } // OK, g returns doubleauto (*fp)() -> auto = f; // OKauto h(); // OK, h's return type will be deduced when it is defined — *end example*]
The auto [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]") can also be used to introduce
a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations"))[.](#general-5.sentence-4)
[6](#general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1906)
A placeholder type can also be used
in the [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") of
the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8New[expr.new]") or
in the [*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]") of a[*new-expression*](expr.new#nt:new-expression "7.6.2.8New[expr.new]") ([[expr.new]](expr.new "7.6.2.8New"))[.](#general-6.sentence-1)
In such a [*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]"),
the placeholder type shall appear
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
the [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") or
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such a [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")[.](#general-6.sentence-2)
[7](#general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1920)
The auto [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]") can also be used
as the [*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]") in an explicit type conversion (functional notation) ([[expr.type.conv]](expr.type.conv "7.6.1.4Explicit type conversion (functional notation)"))[.](#general-7.sentence-1)
[8](#general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1925)
A program that uses a placeholder type in a context not
explicitly allowed in [dcl.spec.auto] is ill-formed[.](#general-8.sentence-1)
[9](#general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1929)
If the [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1General[dcl.decl.general]") contains more than one[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1General[dcl.decl.general]"), they shall all form declarations of
variables[.](#general-9.sentence-1)
The type of each declared variable is determined
by [placeholder type deduction](#def:placeholder_type_deduction "9.2.9.7.2Placeholder type deduction[dcl.type.auto.deduct]"),
and if the type that replaces the placeholder type is not the
same in each deduction, the program is ill-formed[.](#general-9.sentence-2)
[*Example [2](#general-example-2)*: auto x = 5, *y = &x; // OK, auto is intauto a = 5, b = { 1, 2 }; // error: different types for auto — *end example*]
[10](#general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1944)
If a function with a declared return type that contains a placeholder type has
multiple non-discarded return statements, the return type is deduced for each
such return statement[.](#general-10.sentence-1)
If the type deduced is not the same in each
deduction, the program is ill-formed[.](#general-10.sentence-2)
[11](#general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1950)
If a function with a declared return type that uses a placeholder type has no
non-discarded return statements, the return type is deduced as though from areturn statement with no operand at the closing brace of the function
body[.](#general-11.sentence-1)
[*Example [3](#general-example-3)*: auto f() { } // OK, return type is voidauto* g() { } // error: cannot deduce auto* from void() — *end example*]
[12](#general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1962)
An exported function
with a declared return type that uses a placeholder type
shall be defined in the translation unit
containing its exported declaration,
outside the [*private-module-fragment*](module.private.frag#nt:private-module-fragment "10.5Private module fragment[module.private.frag]") (if any)[.](#general-12.sentence-1)
[*Note [2](#general-note-2)*:
The deduced return type cannot have
a name with internal linkage ([[basic.link]](basic.link "6.7Program and linkage"))[.](#general-12.sentence-2)
— *end note*]
[13](#general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1973)
If a variable or function with an undeduced placeholder type is named by an
expression ([[basic.def.odr]](basic.def.odr "6.3One-definition rule")), the program is ill-formed[.](#general-13.sentence-1)
Once a
non-discarded return statement has been seen in a function, however, the return type deduced
from that statement can be used in the rest of the function, including in otherreturn statements[.](#general-13.sentence-2)
[*Example [4](#general-example-4)*: auto n = n; // error: n's initializer refers to nauto f();void g() { &f; } // error: f's return type is unknownauto sum(int i) {if (i == 1)return i; // sum's return type is intelsereturn sum(i-1)+i; // OK, sum's return type has been deduced} — *end example*]
[14](#general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1993)
A result binding never has
an undeduced placeholder type ([[dcl.contract.res]](dcl.contract.res "9.4.2Referring to the result object"))[.](#general-14.sentence-1)
[*Example [5](#general-example-5)*: auto f() post(r : r == 7) // OK{return 7;} — *end example*]
[15](#general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2007)
Return type deduction for a templated
function with a placeholder in its
declared type occurs when the definition is instantiated even if the function
body contains a return statement with a non-type-dependent operand[.](#general-15.sentence-1)
[*Note [3](#general-note-3)*:
Therefore, any use of a specialization of the function template will
cause an implicit instantiation[.](#general-15.sentence-2)
Any errors that arise from this instantiation
are not in the immediate context of the function type and can result in the
program being ill-formed ([[temp.deduct]](temp.deduct "13.10.3Template argument deduction"))[.](#general-15.sentence-3)
— *end note*]
[*Example [6](#general-example-6)*: template <class T> auto f(T t) { return t; } // return type deduced at instantiation timetypedef decltype(f(1)) fint_t; // instantiates f<int> to deduce return typetemplate<class T> auto f(T* t) { return *t; }void g() { int (*p)(int*) = &f; } // instantiates both fs to determine return types,// chooses second — *end example*]
[16](#general-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2028)
If a function or function template F has
a declared return type that uses a placeholder type,
redeclarations or specializations of F shall use that
placeholder type, not a deduced type;
otherwise, they shall not use a placeholder type[.](#general-16.sentence-1)
[*Example [7](#general-example-7)*: auto f();auto f() { return 42; } // return type is intauto f(); // OKint f(); // error: auto and int don't matchdecltype(auto) f(); // error: auto and decltype(auto) don't matchtemplate <typename T> auto g(T t) { return t; } // #1template auto g(int); // OK, return type is inttemplate char g(char); // error: no matching templatetemplate<> auto g(double); // OK, forward declaration with unknown return typetemplate <class T> T g(T t) { return t; } // OK, not functionally equivalent to #1template char g(char); // OK, now there is a matching templatetemplate auto g(float); // still matches #1void h() { return g(42); } // error: ambiguoustemplate <typename T> struct A {friend T frf(T);};auto frf(int i) { return i; } // not a friend of A<int>extern int v;auto v = 17; // OK, redeclares vstruct S {static int i;};auto S::i = 23; // OK — *end example*]
[17](#general-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2066)
A function declared with a return type that uses a placeholder type shall not
be virtual ([[class.virtual]](class.virtual "11.7.3Virtual functions"))[.](#general-17.sentence-1)
[18](#general-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2070)
A function declared with a return type that uses a placeholder type shall not
be a coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions"))[.](#general-18.sentence-1)
[19](#general-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2074)
An [explicit instantiation declaration](temp.explicit "13.9.3Explicit instantiation[temp.explicit]") does not cause the
instantiation of an entity declared using a placeholder type, but it also does
not prevent that entity from being instantiated as needed to determine its
type[.](#general-19.sentence-1)
[*Example [8](#general-example-8)*: template <typename T> auto f(T t) { return t; }extern template auto f(int); // does not instantiate f<int>int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit// instantiation definition is still required somewhere in the program — *end example*]
#### [9.2.9.7.2](#dcl.type.auto.deduct) Placeholder type deduction [[dcl.type.auto.deduct]](dcl.type.auto.deduct)
[1](#dcl.type.auto.deduct-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2091)
[*Placeholder type deduction*](#def:placeholder_type_deduction "9.2.9.7.2Placeholder type deduction[dcl.type.auto.deduct]") is the process by which
a type containing a placeholder type
is replaced by a deduced type[.](#dcl.type.auto.deduct-1.sentence-1)
[2](#dcl.type.auto.deduct-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2097)
A type T containing a placeholder type,
and a corresponding [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[dcl.init.general]") E,
are determined as follows:
- [(2.1)](#dcl.type.auto.deduct-2.1)
For a non-discarded return statement that occurs
in a function declared with a return type
that contains a placeholder type,T is the declared return type[.](#dcl.type.auto.deduct-2.1.sentence-1)
* [(2.1.1)](#dcl.type.auto.deduct-2.1.1)
If the return statement has no operand,
then E is void()[.](#dcl.type.auto.deduct-2.1.1.sentence-1)
* [(2.1.2)](#dcl.type.auto.deduct-2.1.2)
If the operand is a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1General[dcl.init.general]") ([[dcl.init.list]](dcl.init.list "9.5.5List-initialization")),
the program is ill-formed[.](#dcl.type.auto.deduct-2.1.2.sentence-1)
* [(2.1.3)](#dcl.type.auto.deduct-2.1.3)
If the operand is an [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") X that is not an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]"),E is (X)[.](#dcl.type.auto.deduct-2.1.3.sentence-1)
[*Note [1](#dcl.type.auto.deduct-note-1)*:
A comma expression ([[expr.comma]](expr.comma "7.6.20Comma operator")) is not
an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]")[.](#dcl.type.auto.deduct-2.1.3.sentence-2)
— *end note*]
* [(2.1.4)](#dcl.type.auto.deduct-2.1.4)
Otherwise, E is the operand of the return statement[.](#dcl.type.auto.deduct-2.1.4.sentence-1)
If E has type void,T shall be either[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt decltype(auto) orcv [*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto[.](#dcl.type.auto.deduct-2.1.sentence-2)
- [(2.2)](#dcl.type.auto.deduct-2.2)
For a variable declared with a type
that contains a placeholder type,T is the declared type of the variable[.](#dcl.type.auto.deduct-2.2.sentence-1)
* [(2.2.1)](#dcl.type.auto.deduct-2.2.1)
If the initializer of the variable is a [*brace-or-equal-initializer*](dcl.init.general#nt:brace-or-equal-initializer "9.5.1General[dcl.init.general]") of the form = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[dcl.init.general]"),E is the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[dcl.init.general]")[.](#dcl.type.auto.deduct-2.2.1.sentence-1)
* [(2.2.2)](#dcl.type.auto.deduct-2.2.2)
If the initializer is a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1General[dcl.init.general]"),
it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]")[.](#dcl.type.auto.deduct-2.2.2.sentence-1)
* [(2.2.3)](#dcl.type.auto.deduct-2.2.3)
If the initializer is a parenthesized [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]"),
the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]") shall be
a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]")[.](#dcl.type.auto.deduct-2.2.3.sentence-1)
- [(2.3)](#dcl.type.auto.deduct-2.3)
For an explicit type conversion ([[expr.type.conv]](expr.type.conv "7.6.1.4Explicit type conversion (functional notation)")),T is the specified type, which shall be auto[.](#dcl.type.auto.deduct-2.3.sentence-1)
* [(2.3.1)](#dcl.type.auto.deduct-2.3.1)
If the initializer is a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1General[dcl.init.general]"),
it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]")[.](#dcl.type.auto.deduct-2.3.1.sentence-1)
* [(2.3.2)](#dcl.type.auto.deduct-2.3.2)
If the initializer is a parenthesized [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]"),
the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]") shall be
a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]")[.](#dcl.type.auto.deduct-2.3.2.sentence-1)
- [(2.4)](#dcl.type.auto.deduct-2.4)
For a constant template parameter declared with a type
that contains a placeholder type,T is the declared type of the constant template parameter
and E is the corresponding template argument[.](#dcl.type.auto.deduct-2.4.sentence-1)
T shall not be an array type[.](#dcl.type.auto.deduct-2.sentence-2)
[3](#dcl.type.auto.deduct-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2171)
If the [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto,
the deduced typeT′ replacing T is determined using the rules for template argument deduction[.](#dcl.type.auto.deduct-3.sentence-1)
If the initialization is copy-list-initialization,
a declaration of std::initializer_list shall precede ([[basic.lookup.general]](basic.lookup.general "6.5.1General"))
the [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]")[.](#dcl.type.auto.deduct-3.sentence-2)
Obtain P fromT by replacing the occurrence of[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto either with
a new invented type template parameter U or,
if the initialization is copy-list-initialization, withstd::initializer_list<U>[.](#dcl.type.auto.deduct-3.sentence-3)
Deduce a value for U using the rules
of [template argument deduction from a function call](temp.deduct.call "13.10.3.2Deducing template arguments from a function call[temp.deduct.call]"),
where P is a
function template parameter type and
the corresponding argument is E[.](#dcl.type.auto.deduct-3.sentence-4)
If the deduction fails, the declaration is ill-formed[.](#dcl.type.auto.deduct-3.sentence-5)
Otherwise, T′ is obtained by
substituting the deduced U into P[.](#dcl.type.auto.deduct-3.sentence-6)
[*Example [1](#dcl.type.auto.deduct-example-1)*: auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>auto x2 = { 1, 2.0 }; // error: cannot deduce element typeauto x3{ 1, 2 }; // error: not a single elementauto x4 = { 3 }; // decltype(x4) is std::initializer_list<int>auto x5{ 3 }; // decltype(x5) is int — *end example*]
[*Example [2](#dcl.type.auto.deduct-example-2)*: const auto &i = expr;
The type of i is the deduced type of the parameter u in
the call f(expr) of the following invented function template:template <class U> void f(const U& u);
— *end example*]
[4](#dcl.type.auto.deduct-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2215)
If the [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt decltype(auto),T shall be the
placeholder alone[.](#dcl.type.auto.deduct-4.sentence-1)
The type deduced for T is
determined as described in [[dcl.type.decltype]](dcl.type.decltype "9.2.9.6Decltype specifiers"), as thoughE had
been the operand of the decltype[.](#dcl.type.auto.deduct-4.sentence-2)
[*Example [3](#dcl.type.auto.deduct-example-3)*: int i;int&& f();auto x2a(i); // decltype(x2a) is intdecltype(auto) x2d(i); // decltype(x2d) is intauto x3a = i; // decltype(x3a) is intdecltype(auto) x3d = i; // decltype(x3d) is intauto x4a = (i); // decltype(x4a) is intdecltype(auto) x4d = (i); // decltype(x4d) is int&auto x5a = f(); // decltype(x5a) is intdecltype(auto) x5d = f(); // decltype(x5d) is int&&auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>decltype(auto) x6d = { 1, 2 }; // error: { 1, 2 } is not an expressionauto *x7a = &i; // decltype(x7a) is int*decltype(auto)*x7d = &i; // error: declared type is not plain decltype(auto)auto f1(int x) -> decltype((x)) { return (x); } // return type is int&auto f2(int x) -> decltype(auto) { return (x); } // return type is int&& — *end example*]
[5](#dcl.type.auto.deduct-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2244)
For a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") with a [*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]"),
the immediately-declared constraint ([[temp.param]](temp.param "13.2Template parameters"))
of the [*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]") for the type deduced for the placeholder
shall be satisfied[.](#dcl.type.auto.deduct-5.sentence-1)