[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.1 General [dcl.spec.auto.general]") [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")opt auto [*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [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.6 Functions [dcl.fct]") of a - [(2.1)](#general-2.1) function declaration ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")), - [(2.2)](#general-2.2) [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6 Lambda expressions")), or - [(2.3)](#general-2.3) [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template parameters")) can be declared using a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]") of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [dcl.spec.general]")*s* in the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") or as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") that specifies the type that replaces such a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1 General [dcl.spec.general]") (see below); the placeholder type is a [*generic parameter type placeholder*](#def:generic_parameter_type_placeholder "9.2.9.7.1 General [dcl.spec.auto.general]") of the function declaration,[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"), or[*template-parameter*](temp.param#nt:template-parameter "13.2 Template 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.6 Functions")) or the lambda is a generic lambda ([[expr.prim.lambda]](expr.prim.lambda "7.5.6 Lambda 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.1 General [dcl.spec.general]") for a function declarator that includes a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#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.1 General [dcl.spec.general]") or [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1 General [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.2 The 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.5 Initializers")) 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.1 General [dcl.spec.general]")*s* in the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") or as one of the[*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") that specifies the type that replaces such a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1 General [dcl.spec.general]"); the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") shall be followed by one or more[*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]")*s*, each of which shall be followed by a non-empty[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [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.2 Storage 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.1 General [dcl.type.general]") can also be used to introduce a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured 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.1 General [dcl.type.general]") of the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8 New [expr.new]") or in the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") of a[*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") ([[expr.new]](expr.new "7.6.2.8 New"))[.](#general-6.sentence-1) In such a [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]"), the placeholder type shall appear as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in the [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]") or as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") that specifies the type that replaces such a [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1 General [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.1 General [dcl.type.general]") can also be used as the [*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") in an explicit type conversion (functional notation) ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit 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.1 General [dcl.decl.general]") contains more than one[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1 General [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.2 Placeholder 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.5 Private 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.7 Program 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.3 One-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.2 Referring 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.3 Template argument deduction"))[.](#general-15.sentence-3) — *end note*] [*Example [6](#general-example-6)*: template auto f(T t) { return t; } // return type deduced at instantiation timetypedef decltype(f(1)) fint_t; // instantiates f to deduce return typetemplate 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 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 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 struct A {friend T frf(T);};auto frf(int i) { return i; } // not a friend of Aextern 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.3 Virtual 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.4 Coroutine 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.3 Explicit 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 auto f(T t) { return t; }extern template auto f(int); // does not instantiate fint (*p)(int) = f; // instantiates f 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.2 Placeholder 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.1 General [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.1 General [dcl.init.general]") ([[dcl.init.list]](dcl.init.list "9.5.5 List-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.20 Comma operator [expr.comma]") X that is not an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.20 Comma operator")) is not an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.2 Template parameters [temp.param]")opt decltype(auto) orcv [*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [dcl.init.general]") of the form = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]"),E is the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [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.1 General [dcl.init.general]"), it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.1 General [expr.post.general]"), the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") shall be a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.4 Explicit 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.1 General [dcl.init.general]"), it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.1 General [expr.post.general]"), the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") shall be a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.1 General [dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General")) the [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [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.2 Template 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[.](#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.2 Deducing 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_listauto x2 = { 1, 2.0 }; // error: cannot deduce element typeauto x3{ 1, 2 }; // error: not a single elementauto x4 = { 3 }; // decltype(x4) is std​::​initializer_listauto 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 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.1 General [dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.6 Decltype 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_listdecltype(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.1 General [dcl.spec.auto.general]") with a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]"), the immediately-declared constraint ([[temp.param]](temp.param "13.2 Template parameters")) of the [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") for the type deduced for the placeholder shall be satisfied[.](#dcl.type.auto.deduct-5.sentence-1)