[dcl.spec.auto] (original) (raw)

9 Declarations [dcl.dcl]

9.2 Specifiers [dcl.spec]

9.2.9 Type specifiers [dcl.type]

9.2.9.7 Placeholder type specifiers [dcl.spec.auto]

9.2.9.7.1 General [dcl.spec.auto.general]

A placeholder-type-specifierdesignates a placeholder type that will be replaced later, typically by deduction from an initializer.

[Note 1:

Having a generic parameter type placeholder signifies that the function is an abbreviated function template ([dcl.fct]) or the lambda is a generic lambda ([expr.prim.lambda]).

— _end note_]

A placeholder type can appear in the decl-specifier-seq or type-specifier-seqin 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]).

The type of a variable declared using a placeholder type is deduced from its initializer.

This use is allowed in an initializing declaration ([dcl.init]) of a variable.

[Example 1: auto x = 5; const auto *v = &x, u = 6; static auto y = 0.0; auto int r; auto f() -> int; auto g() { return 0.0; } auto (*fp)() -> auto = f; auto h(); — _end example_]

A program that uses a placeholder type in a context not explicitly allowed in [dcl.spec.auto] is ill-formed.

The type of each declared variable is determined by placeholder type deduction, and if the type that replaces the placeholder type is not the same in each deduction, the program is ill-formed.

[Example 2: auto x = 5, *y = &x; auto a = 5, b = { 1, 2 }; — _end example_]

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.

If the type deduced is not the same in each deduction, the program is ill-formed.

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.

[Example 3: auto f() { } auto* g() { } — _end example_]

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 (if any).

[Note 2:

The deduced return type cannot have a name with internal linkage ([basic.link]).

— _end note_]

If a variable or function with an undeduced placeholder type is named by an expression ([basic.def.odr]), the program is ill-formed.

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.

[Example 4: auto n = n; auto f();void g() { &f; } auto sum(int i) { if (i == 1) return i; else return sum(i-1)+i; } — _end example_]

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.

[Note 3:

Therefore, any use of a specialization of the function template will cause an implicit instantiation.

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]).

— _end note_]

[Example 5: template <class T> auto f(T t) { return t; } typedef decltype(f(1)) fint_t; template<class T> auto f(T* t) { return *t; } void g() { int (*p)(int*) = &f; } — _end example_]

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.

[Example 6: auto f();auto f() { return 42; } auto f(); int f(); decltype(auto) f(); template <typename T> auto g(T t) { return t; } template auto g(int); template char g(char); template<> auto g(double); template <class T> T g(T t) { return t; } template char g(char); template auto g(float); void h() { return g(42); } template <typename T> struct A { friend T frf(T);};auto frf(int i) { return i; } extern int v;auto v = 17; struct S { static int i;};auto S::i = 23; — _end example_]

A function declared with a return type that uses a placeholder type shall not be virtual ([class.virtual]).

A function declared with a return type that uses a placeholder type shall not be a coroutine ([dcl.fct.def.coroutine]).

An explicit instantiation declaration 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.

[Example 7: template <typename T> auto f(T t) { return t; } extern template auto f(int); int (*p)(int) = f; — _end example_]

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

Placeholder type deductionis 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-clause E, are determined as follows:

T shall not be an array type.

If the placeholder-type-specifier is of the formtype-constraint auto, the deduced type replacing Tis determined using the rules for template argument deduction.

If the initialization is copy-list-initialization, a declaration of std​::​initializer_listshall precede ([basic.lookup.general]) the placeholder-type-specifier.

Obtain P fromT by replacing the occurrences oftype-constraint auto either with a new invented type template parameter U or, if the initialization is copy-list-initialization, withstd​::​initializer_list<U>.

If the deduction fails, the declaration is ill-formed.

Otherwise, is obtained by substituting the deduced U into P.

[Example 1: auto x1 = { 1, 2 }; auto x2 = { 1, 2.0 }; auto x3{ 1, 2 }; auto x4 = { 3 }; auto x5{ 3 }; — _end example_]

[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_]

If the placeholder-type-specifier is of the formtype-constraint decltype(auto),T shall be the placeholder alone.

The type deduced for T is determined as described in [dcl.type.decltype], as thoughE had been the operand of the decltype.

[Example 3: int i;int&& f();auto x2a(i); decltype(auto) x2d(i); auto x3a = i; decltype(auto) x3d = i; auto x4a = (i); decltype(auto) x4d = (i); auto x5a = f(); decltype(auto) x5d = f(); auto x6a = { 1, 2 }; decltype(auto) x6d = { 1, 2 }; auto *x7a = &i; decltype(auto)*x7d = &i; auto f1(int x) -> decltype((x)) { return (x); } auto f2(int x) -> decltype(auto) { return (x); } — _end example_]