7 Declarations [dcl.dcl]

7.1 Specifiers [dcl.spec]

7.1.7 Type specifiers [dcl.type]

7.1.7.4 The auto specifier [dcl.spec.auto]

7.1.7.4.1 Placeholder type deduction [dcl.type.auto.deduct]

Placeholder type deduction is the process by which a type containing a placeholder type is replaced by a deduced type.

A type T containing a placeholder type, and a corresponding initializer e, are determined as follows:

  • 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 and e is the operand of the return statement. If the return statement has no operand, then e is void();

  • for a variable declared with a type that contains a placeholder type, T is the declared type of the variable and e is the initializer. If the initialization is direct-list-initialization, the initializer shall be a braced-init-list containing only a single assignment-expression and e is the assignment-expression;

  • for a non-type template parameter declared with a type that contains a placeholder type, T is the declared type of the non-type template parameter and e is the corresponding template argument.

In the case of a return statement with no operand or with an operand of type void, T shall be either decltype(auto) or cv auto.

If the deduction is for a return statement and e is a braced-init-list ([dcl.init.list]), the program is ill-formed.

If the placeholder is the auto type-specifier, the deduced type T' replacing T is determined using the rules for template argument deduction. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initialization is copy-list-initialization, with std::initializer_list<U>. Deduce a value for U using the rules of template argument deduction from a function call ([temp.deduct.call]), where P is a function template parameter type and the corresponding argument is e. If the deduction fails, the declaration is ill-formed. Otherwise, T' is obtained by substituting the deduced U into P. [ Example:

auto x1 = { 1, 2 };         // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 };       // error: cannot deduce element type
auto x3{ 1, 2 };            // error: not a single element
auto x4 = { 3 };            // decltype(x4) is std::initializer_list<int>
auto x5{ 3 };               // decltype(x5) is int

 — end example ]

Example:

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 ]

If the placeholder is the decltype(auto) type-specifier, T shall be the placeholder alone. The type deduced for T is determined as described in [dcl.type.simple], as though e had been the operand of the decltype. [ Example:

int i;
int&& f();
auto           x2a(i);         // decltype(x2a) is int
decltype(auto) x2d(i);         // decltype(x2d) is int
auto           x3a = i;        // decltype(x3a) is int
decltype(auto) x3d = i;        // decltype(x3d) is int
auto           x4a = (i);      // decltype(x4a) is int
decltype(auto) x4d = (i);      // decltype(x4d) is int&
auto           x5a = f();      // decltype(x5a) is int
decltype(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 expression
auto          *x7a = &i;       // decltype(x7a) is int*
decltype(auto)*x7d = &i;       // error, declared type is not plain decltype(auto)

 — end example ]