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

9 Declarations [dcl.dcl]

9.2 Specifiers [dcl.spec]

9.2.8 Type specifiers [dcl.type]

9.2.8.5 Placeholder type specifiers [dcl.spec.auto]

placeholder-type-specifier: type-constraint auto type-constraint decltype ( auto )

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

[ Note

:

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

]

Otherwise, the function declarator shall declare a function.

If the declared return type of the function contains a placeholder type, 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

:

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 h();

end example

]

A program that uses a placeholder type in a context not explicitly allowed in this subclause 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

:

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

:

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

:

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

end note

]

If the name of an entity with an undeduced placeholder type appears in an expression, 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

:

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 entity that is a function or function template 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

:

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

:

template auto f(T t) { return t; }
typedef decltype(f(1)) fint_t;
template auto f(T* t) { return *t; } void g() { int (p)(int) = &f; }

end example

]

Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type.

Similarly, redeclarations or specializations of a function or function template with a declared return type that does not use a placeholder type shall not use a placeholder.

[ Example

:

auto f(); auto f() { return 42; }
auto f();
int f();
decltype(auto) f();

template auto g(T t) { return t; } template auto g(int);
template char g(char);
template<> auto g(double);

template T g(T t) { return t; }
template char g(char);
template auto g(float);

void h() { return g(42); }

template 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.

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

:

template auto f(T t) { return t; } extern template auto f(int);
int (*p)(int) = f;

end example

]

9.2.8.5.1 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 E, are determined as follows:

In the case of a return statement with no operand or with an operand of type void,T shall be eithertype-constraint decltype(auto) orcv type-constraint auto.

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

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

:

auto x1 = { 1, 2 };
auto x2 = { 1, 2.0 };
auto x3{ 1, 2 };
auto x4 = { 3 };
auto x5{ 3 };

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 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.simple], as thoughE had been the operand of the decltype.

[ Example

:

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;

end example

]