[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 <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.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 <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.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<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.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_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.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_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.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)
