This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

412
cppdraft/dcl/spec/auto.md Normal file
View File

@@ -0,0 +1,412 @@
[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.1General[dcl.spec.auto.general]")
[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto
[*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.1General[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.6Functions[dcl.fct]") of a
- [(2.1)](#general-2.1)
function declaration ([[dcl.fct]](dcl.fct "9.3.4.6Functions")),
- [(2.2)](#general-2.2)
[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda expressions")), or
- [(2.3)](#general-2.3)
[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") ([[temp.param]](temp.param "13.2Template parameters"))
can be declared using
a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.1General[dcl.spec.general]")*s* in
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such
a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]") (see below);
the placeholder type
is a [*generic parameter type placeholder*](#def:generic_parameter_type_placeholder "9.2.9.7.1General[dcl.spec.auto.general]") of the
function declaration,[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"), or[*template-parameter*](temp.param#nt:template-parameter "13.2Template 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.6Functions")) or
the lambda is a generic lambda ([[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda 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.1General[dcl.spec.general]") for a function declarator
that includes a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") ([[dcl.fct]](dcl.fct "9.3.4.6Functions"))[.](#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.1General[dcl.spec.general]") or [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[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.2The 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.5Initializers")) 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.1General[dcl.spec.general]")*s* in the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or as one of the[*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]");
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") shall be followed by one or more[*declarator*](dcl.decl.general#nt:declarator "9.3.1General[dcl.decl.general]")*s*,
each of which shall
be followed by a non-empty[*initializer*](dcl.init.general#nt:initializer "9.5.1General[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.2Storage 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.1General[dcl.type.general]") can also be used to introduce
a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured 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.1General[dcl.type.general]") of
the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8New[expr.new]") or
in the [*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]") of a[*new-expression*](expr.new#nt:new-expression "7.6.2.8New[expr.new]") ([[expr.new]](expr.new "7.6.2.8New"))[.](#general-6.sentence-1)
In such a [*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]"),
the placeholder type shall appear
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
the [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") or
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such a [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[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.1General[dcl.type.general]") can also be used
as the [*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]") in an explicit type conversion (functional notation) ([[expr.type.conv]](expr.type.conv "7.6.1.4Explicit 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.1General[dcl.decl.general]") contains more than one[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1General[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.2Placeholder 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.5Private 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.7Program 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.3One-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.2Referring 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.3Template 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.3Virtual 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.4Coroutine 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.3Explicit 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.2Placeholder 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.1General[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.1General[dcl.init.general]") ([[dcl.init.list]](dcl.init.list "9.5.5List-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.20Comma operator[expr.comma]") X that is not an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment 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.20Comma operator")) is not
an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment 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.2Template parameters[temp.param]")opt decltype(auto) orcv [*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.1General[dcl.init.general]") of the form = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[dcl.init.general]"),E is the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[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.1General[dcl.init.general]"),
it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment 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.1General[expr.post.general]"),
the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]") shall be
a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment 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.4Explicit 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.1General[dcl.init.general]"),
it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment 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.1General[expr.post.general]"),
the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]") shall be
a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment and compound assignment operators[expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19Assignment 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.1General[dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.1General"))
the [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[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.2Template 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.2Deducing 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.1General[dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.6Decltype 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.1General[dcl.spec.auto.general]") with a [*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]"),
the immediately-declared constraint ([[temp.param]](temp.param "13.2Template parameters"))
of the [*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]") for the type deduced for the placeholder
shall be satisfied[.](#dcl.type.auto.deduct-5.sentence-1)

View File

@@ -0,0 +1,264 @@
[dcl.spec.auto.general]
# 9 Declarations [[dcl]](./#dcl)
## 9.2 Specifiers [[dcl.spec]](dcl.spec#auto.general)
### 9.2.9 Type specifiers [[dcl.type]](dcl.type#dcl.spec.auto.general)
#### 9.2.9.7 Placeholder type specifiers [[dcl.spec.auto]](dcl.spec.auto#general)
#### 9.2.9.7.1 General [dcl.spec.auto.general]
[placeholder-type-specifier:](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]")
[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto
[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt decltype ( auto )
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1825)
A [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") designates a placeholder type that will be replaced later,
typically by deduction
from an initializer[.](#1.sentence-1)
[2](#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.6Functions[dcl.fct]") of a
- [(2.1)](#2.1)
function declaration ([[dcl.fct]](dcl.fct "9.3.4.6Functions")),
- [(2.2)](#2.2)
[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda expressions")), or
- [(2.3)](#2.3)
[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") ([[temp.param]](temp.param "13.2Template parameters"))
can be declared using
a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") of the form[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]")opt auto[.](#2.sentence-1)
The placeholder type shall appear
as one of the [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such
a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]") (see below);
the placeholder type
is a [*generic parameter type placeholder*](#def:generic_parameter_type_placeholder "9.2.9.7.1General[dcl.spec.auto.general]") of the
function declaration,[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"), or[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]"), respectively[.](#2.sentence-2)
[*Note [1](#note-1)*:
Having a generic parameter type placeholder
signifies that the function is
an abbreviated function template ([[dcl.fct]](dcl.fct "9.3.4.6Functions")) or
the lambda is a generic lambda ([[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda expressions"))[.](#2.sentence-3)
— *end note*]
[3](#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.1General[dcl.spec.general]") for a function declarator
that includes a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") ([[dcl.fct]](dcl.fct "9.3.4.6Functions"))[.](#3.sentence-1)
[4](#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.1General[dcl.spec.general]") or [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[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.2The if statement"))[.](#4.sentence-1)
[5](#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[.](#5.sentence-1)
This use is allowed
in an initializing declaration ([[dcl.init]](dcl.init "9.5Initializers")) of a variable[.](#5.sentence-2)
The placeholder type shall appear as one of the[*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or as one of the[*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such a [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]");
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") shall be followed by one or more[*declarator*](dcl.decl.general#nt:declarator "9.3.1General[dcl.decl.general]")*s*,
each of which shall
be followed by a non-empty[*initializer*](dcl.init.general#nt:initializer "9.5.1General[dcl.init.general]")[.](#5.sentence-3)
[*Example [1](#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.2Storage 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.1General[dcl.type.general]") can also be used to introduce
a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations"))[.](#5.sentence-4)
[6](#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.1General[dcl.type.general]") of
the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8New[expr.new]") or
in the [*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]") of a[*new-expression*](expr.new#nt:new-expression "7.6.2.8New[expr.new]") ([[expr.new]](expr.new "7.6.2.8New"))[.](#6.sentence-1)
In such a [*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]"),
the placeholder type shall appear
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
the [*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") or
as one of the [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1General[dcl.decl.general]") that specifies the type that replaces such a [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]")[.](#6.sentence-2)
[7](#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.1General[dcl.type.general]") can also be used
as the [*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]") in an explicit type conversion (functional notation) ([[expr.type.conv]](expr.type.conv "7.6.1.4Explicit type conversion (functional notation)"))[.](#7.sentence-1)
[8](#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]](dcl.spec.auto "9.2.9.7Placeholder type specifiers") is ill-formed[.](#8.sentence-1)
[9](#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.1General[dcl.decl.general]") contains more than one[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1General[dcl.decl.general]"), they shall all form declarations of
variables[.](#9.sentence-1)
The type of each declared variable is determined
by [placeholder type deduction](dcl.type.auto.deduct#def:placeholder_type_deduction "9.2.9.7.2Placeholder 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[.](#9.sentence-2)
[*Example [2](#example-2)*: auto x = 5, *y = &x; // OK, auto is intauto a = 5, b = { 1, 2 }; // error: different types for auto — *end example*]
[10](#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[.](#10.sentence-1)
If the type deduced is not the same in each
deduction, the program is ill-formed[.](#10.sentence-2)
[11](#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[.](#11.sentence-1)
[*Example [3](#example-3)*: auto f() { } // OK, return type is voidauto* g() { } // error: cannot deduce auto* from void() — *end example*]
[12](#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.5Private module fragment[module.private.frag]") (if any)[.](#12.sentence-1)
[*Note [2](#note-2)*:
The deduced return type cannot have
a name with internal linkage ([[basic.link]](basic.link "6.7Program and linkage"))[.](#12.sentence-2)
— *end note*]
[13](#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.3One-definition rule")), the program is ill-formed[.](#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[.](#13.sentence-2)
[*Example [4](#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](#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.2Referring to the result object"))[.](#14.sentence-1)
[*Example [5](#example-5)*: auto f() post(r : r == 7) // OK{return 7;} — *end example*]
[15](#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[.](#15.sentence-1)
[*Note [3](#note-3)*:
Therefore, any use of a specialization of the function template will
cause an implicit instantiation[.](#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.3Template argument deduction"))[.](#15.sentence-3)
— *end note*]
[*Example [6](#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](#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[.](#16.sentence-1)
[*Example [7](#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](#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.3Virtual functions"))[.](#17.sentence-1)
[18](#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.4Coroutine definitions"))[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2074)
An [explicit instantiation declaration](temp.explicit "13.9.3Explicit 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[.](#19.sentence-1)
[*Example [8](#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*]

View File

@@ -0,0 +1,82 @@
[dcl.spec.general]
# 9 Declarations [[dcl]](./#dcl)
## 9.2 Specifiers [[dcl.spec]](dcl.spec#general)
### 9.2.1 General [dcl.spec.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L431)
The specifiers that can be used in a declaration are
[decl-specifier:](#nt:decl-specifier "9.2.1General[dcl.spec.general]")
[*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]")
[*defining-type-specifier*](dcl.type.general#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]")
[*function-specifier*](dcl.fct.spec#nt:function-specifier "9.2.3Function specifiers[dcl.fct.spec]")
friend
typedef
constexpr
consteval
constinit
inline
[decl-specifier-seq:](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")
[*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt
[*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]") [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")
The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") appertains to the type determined by the preceding[*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* ([[dcl.meaning]](dcl.meaning "9.3.4Meaning of declarators"))[.](#1.sentence-2)
The [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") affects the type only for the declaration it appears in, not other declarations involving the
same type[.](#1.sentence-3)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L459)
At most one of each of the [*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s*friend, typedef, or inline shall appear in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")[.](#2.sentence-1)
At most one of
the constexpr, consteval, and constinit keywords
shall appear in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L467)
If a [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]") is encountered while parsing a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]"),
it is interpreted as part of the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") if and only if there is no
previous [*defining-type-specifier*](dcl.type.general#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]") other than a [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]") in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")[.](#3.sentence-1)
The sequence shall be self-consistent as
described below[.](#3.sentence-2)
[*Example [1](#example-1)*: typedef char* Pc;static Pc; // error: name missing
Here, the declaration static Pc is ill-formed because no
name was specified for the static variable of type Pc[.](#3.sentence-3)
To get a
variable called Pc, a [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1General[dcl.type.general]") (other thanconst or volatile) has to be present to indicate that
the [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") Pc is the name being (re)declared,
rather than being part of the [*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]") sequence[.](#3.sentence-4)
For
another example,void f(const Pc); // void f(char* const) (not const char*)void g(const int Pc); // void g(const int)
— *end example*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L493)
[*Note [1](#note-1)*:
Since signed, unsigned, long, and short by default imply int, a [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]") appearing after one
of those specifiers is treated as the name being (re)declared[.](#4.sentence-1)
[*Example [2](#example-2)*: void h(unsigned Pc); // void h(unsigned int)void k(unsigned int Pc); // void k(unsigned int) — *end example*]
— *end note*]