Files
cppdraft_translate/cppdraft/dcl/spec.md
2025-10-25 03:02:53 +03:00

1815 lines
118 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[dcl.spec]
# 9 Declarations [[dcl]](./#dcl)
## 9.2 Specifiers [dcl.spec]
### [9.2.1](#general) General [[dcl.spec.general]](dcl.spec.general)
[1](#general-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*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]")
[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]")
[*function-specifier*](#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"))[.](#general-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[.](#general-1.sentence-3)
[2](#general-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]")[.](#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]")[.](#general-2.sentence-2)
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L467)
If a [*type-name*](#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*](#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]")[.](#general-3.sentence-1)
The sequence shall be self-consistent as
described below[.](#general-3.sentence-2)
[*Example [1](#general-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[.](#general-3.sentence-3)
To get a
variable called Pc, a [*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") (other thanconst or volatile) has to be present to indicate that
the [*typedef-name*](#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[.](#general-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](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L493)
[*Note [1](#general-note-1)*:
Since signed, unsigned, long, and short by default imply int, a [*type-name*](#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[.](#general-4.sentence-1)
[*Example [2](#general-example-2)*: void h(unsigned Pc); // void h(unsigned int)void k(unsigned int Pc); // void k(unsigned int) — *end example*]
— *end note*]
### [9.2.2](#dcl.stc) Storage class specifiers [[dcl.stc]](dcl.stc)
[1](#dcl.stc-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L518)
The storage class specifiers are
[storage-class-specifier:](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]")
static
thread_local
extern
mutable
At most one [*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") shall appear in a given[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]"), except that thread_local may appear with static orextern[.](#dcl.stc-1.sentence-2)
If thread_local appears in any declaration of
a variable it shall be present in all declarations of that entity[.](#dcl.stc-1.sentence-3)
If a[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") appears in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]"), there can be notypedef specifier in the same [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") and
the [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1General[dcl.decl.general]") or [*member-declarator-list*](class.mem.general#nt:member-declarator-list "11.4.1General[class.mem.general]") of the declaration shall not be
empty (except for an anonymous union declared in a namespace scope ([[class.union.anon]](class.union.anon "11.5.2Anonymous unions")))[.](#dcl.stc-1.sentence-4)
The[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") applies to the name declared by each[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1General[dcl.decl.general]") in the list and not to any names declared by
other specifiers[.](#dcl.stc-1.sentence-5)
[*Note [1](#dcl.stc-note-1)*:
See [[temp.expl.spec]](temp.expl.spec "13.9.4Explicit specialization") and [[temp.explicit]](temp.explicit "13.9.3Explicit instantiation") for restrictions
in explicit specializations and explicit instantiations, respectively[.](#dcl.stc-1.sentence-6)
— *end note*]
[2](#dcl.stc-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L546)
[*Note [2](#dcl.stc-note-2)*:
A variable declared without a [*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") at block scope or declared as a function parameter
has [automatic storage duration](basic.stc.auto#def:storage_duration,automatic "6.8.6.4Automatic storage duration[basic.stc.auto]") by default[.](#dcl.stc-2.sentence-1)
— *end note*]
[3](#dcl.stc-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L553)
The thread_local specifier
indicates that the named entity has thread storage duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3Thread storage duration"))[.](#dcl.stc-3.sentence-1)
It
shall be applied only
to the declaration of a variable of namespace or block scope,
to a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations")), or
to the declaration of a static data member[.](#dcl.stc-3.sentence-2)
When thread_local is applied to a variable of block scope the[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") static is implied if no other[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") appears in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")[.](#dcl.stc-3.sentence-3)
[4](#dcl.stc-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L565)
The static specifier shall be applied only
to the declaration of a variable or function,
to a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations")), or
to the declaration of an anonymous union ([[class.union.anon]](class.union.anon "11.5.2Anonymous unions"))[.](#dcl.stc-4.sentence-1)
There can be nostatic function declarations within a block, nor anystatic function parameters[.](#dcl.stc-4.sentence-2)
A static specifier used in
the declaration of a variable declares the variable to have static storage
duration ([[basic.stc.static]](basic.stc.static "6.8.6.2Static storage duration")), unless accompanied by thethread_local specifier, which declares the variable to have thread
storage duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3Thread storage duration"))[.](#dcl.stc-4.sentence-3)
A static specifier can be
used in declarations of class members; [[class.static]](class.static "11.4.9Static members") describes its
effect[.](#dcl.stc-4.sentence-4)
For the linkage of a name declared with a static specifier,
see [[basic.link]](basic.link "6.7Program and linkage")[.](#dcl.stc-4.sentence-5)
[5](#dcl.stc-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L584)
The extern specifier shall be applied only to the declaration of a variable
or function[.](#dcl.stc-5.sentence-1)
The extern specifier shall not be used in the
declaration of a class member or function parameter[.](#dcl.stc-5.sentence-2)
For the linkage of a name declared with an extern specifier,
see [[basic.link]](basic.link "6.7Program and linkage")[.](#dcl.stc-5.sentence-3)
[*Note [3](#dcl.stc-note-3)*:
The extern keyword can also be used in[*explicit-instantiation*](temp.explicit#nt:explicit-instantiation "13.9.3Explicit instantiation[temp.explicit]")*s* and[*linkage-specification*](dcl.link#nt:linkage-specification "9.12Linkage specifications[dcl.link]")*s*, but it is not a[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]") in such contexts[.](#dcl.stc-5.sentence-4)
— *end note*]
[6](#dcl.stc-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L600)
All declarations for a given entity shall give its name the same linkage[.](#dcl.stc-6.sentence-1)
[*Note [4](#dcl.stc-note-4)*:
The linkage given by some declarations is affected by previous declarations[.](#dcl.stc-6.sentence-2)
Overloads are distinct entities[.](#dcl.stc-6.sentence-3)
— *end note*]
[*Example [1](#dcl.stc-example-1)*: static char* f(); // f() has internal linkagechar* f() // f() still has internal linkage{ /* ... */ }char* g(); // g() has external linkagestatic char* g() // error: inconsistent linkage{ /* ... */ }void h();inline void h(); // external linkageinline void l();void l(); // external linkageinline void m();extern void m(); // external linkagestatic void n();inline void n(); // internal linkagestatic int a; // a has internal linkageint a; // error: two definitionsstatic int b; // b has internal linkageextern int b; // b still has internal linkageint c; // c has external linkagestatic int c; // error: inconsistent linkageextern int d; // d has external linkagestatic int d; // error: inconsistent linkage — *end example*]
[7](#dcl.stc-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L642)
The name of a declared but undefined class can be used in anextern declaration[.](#dcl.stc-7.sentence-1)
Such a declaration can only be used in ways
that do not require a complete class type[.](#dcl.stc-7.sentence-2)
[*Example [2](#dcl.stc-example-2)*: struct S;extern S a;extern S f();extern void g(S);
void h() { g(a); // error: S is incomplete f(); // error: S is incomplete} — *end example*]
[8](#dcl.stc-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L661)
The mutable specifier shall appear only in the declaration of
a non-static data member ([[class.mem]](class.mem "11.4Class members"))
whose type is neither const-qualified nor a reference type[.](#dcl.stc-8.sentence-1)
[*Example [3](#dcl.stc-example-3)*: class X {mutable const int* p; // OKmutable int* const q; // error}; — *end example*]
[9](#dcl.stc-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L674)
[*Note [5](#dcl.stc-note-5)*:
The mutable specifier on a class data member nullifies aconst specifier applied to the containing class object and
permits modification of the mutable class member even though the rest of
the object is const ([[basic.type.qualifier]](basic.type.qualifier "6.9.5CV-qualifiers"), [[dcl.type.cv]](#dcl.type.cv "9.2.9.2The cv-qualifiers"))[.](#dcl.stc-9.sentence-1)
— *end note*]
### [9.2.3](#dcl.fct.spec) Function specifiers [[dcl.fct.spec]](dcl.fct.spec)
[1](#dcl.fct.spec-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L689)
A[*function-specifier*](#nt:function-specifier "9.2.3Function specifiers[dcl.fct.spec]") can be used only in a function declaration[.](#dcl.fct.spec-1.sentence-1)
At most one [*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]") and
at most one virtual keyword shall appear in
a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")[.](#dcl.fct.spec-1.sentence-2)
[function-specifier:](#nt:function-specifier "9.2.3Function specifiers[dcl.fct.spec]")
virtual
[*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]")
[explicit-specifier:](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]")
explicit ( [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") )
explicit
[2](#dcl.fct.spec-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L709)
The virtual specifier shall be used only in the initial
declaration of a non-static member function; see [[class.virtual]](class.virtual "11.7.3Virtual functions")[.](#dcl.fct.spec-2.sentence-1)
[3](#dcl.fct.spec-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L714)
An [*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]") shall be used only in the declaration of
a constructor or conversion function within its class definition;
see [[class.conv.ctor]](class.conv.ctor "11.4.8.2Conversion by constructor") and [[class.conv.fct]](class.conv.fct "11.4.8.3Conversion functions")[.](#dcl.fct.spec-3.sentence-1)
[4](#dcl.fct.spec-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L720)
In an [*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]"),
the [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]"), if supplied, shall be a
contextually converted constant expression of type bool ([[expr.const]](expr.const "7.7Constant expressions"))[.](#dcl.fct.spec-4.sentence-1)
The [*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]") explicit without a [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") is equivalent to
the [*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]") explicit(true)[.](#dcl.fct.spec-4.sentence-2)
If the constant expression evaluates to true,
the function is explicit[.](#dcl.fct.spec-4.sentence-3)
Otherwise, the function is not explicit[.](#dcl.fct.spec-4.sentence-4)
A ( token that follows explicit is parsed as
part of the [*explicit-specifier*](#nt:explicit-specifier "9.2.3Function specifiers[dcl.fct.spec]")[.](#dcl.fct.spec-4.sentence-5)
[*Example [1](#dcl.fct.spec-example-1)*: struct S {explicit(sizeof(char[2])) S(char); // error: narrowing conversion of value 2 to type boolexplicit(sizeof(char)) S(bool); // OK, conversion of value 1 to type bool is non-narrowing}; — *end example*]
### [9.2.4](#dcl.typedef) The typedef specifier [[dcl.typedef]](dcl.typedef)
[1](#dcl.typedef-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L743)
Declarations containing the [*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]") typedef declare [*type aliases*](#def:alias,type "9.2.4The typedef specifier[dcl.typedef]")[.](#dcl.typedef-1.sentence-1)
The typedef specifier shall not be
combined in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") with any other kind of
specifier except a [*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]"), and it shall not be used in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") of a[*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6Functions[dcl.fct]") ([[dcl.fct]](dcl.fct "9.3.4.6Functions")) nor in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") of a[*function-definition*](dcl.fct.def.general#nt:function-definition "9.6.1General[dcl.fct.def.general]") ([[dcl.fct.def]](dcl.fct.def "9.6Function definitions"))[.](#dcl.typedef-1.sentence-2)
If a typedef specifier appears in a declaration without a [*declarator*](dcl.decl.general#nt:declarator "9.3.1General[dcl.decl.general]"),
the program is ill-formed[.](#dcl.typedef-1.sentence-3)
[typedef-name:](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]")
[*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")
[*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
A name declared with the typedef specifier becomes a[*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]")[.](#dcl.typedef-1.sentence-4)
The underlying entity of the type alias is
the type associated with the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") ([[dcl.decl]](dcl.decl "9.3Declarators"))
or [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") ([[temp.pre]](temp.pre "13.1Preamble"))[.](#dcl.typedef-1.sentence-5)
A [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") does not introduce a new type the way a class
declaration ([[class.name]](class.name "11.3Class names")) or enum declaration ([[dcl.enum]](dcl.enum "9.8.1Enumeration declarations")) does[.](#dcl.typedef-1.sentence-6)
[*Example [1](#dcl.typedef-example-1)*:
Aftertypedef int MILES, *KLICKSP; the constructionsMILES distance;extern KLICKSP metricp; are all correct declarations; the type of distance isint and that of metricp is “pointer to int”[.](#dcl.typedef-1.sentence-7)
— *end example*]
[2](#dcl.typedef-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L785)
A type alias can also be declared by an[*alias-declaration*](dcl.pre#nt:alias-declaration "9.1Preamble[dcl.pre]")[.](#dcl.typedef-2.sentence-1)
The [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") following theusing keyword is not looked up;
it becomes the [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") of a type alias
and the optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") following the[*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") appertains to that type alias[.](#dcl.typedef-2.sentence-2)
Such a type alias has the same
semantics as if it were introduced by the typedef specifier[.](#dcl.typedef-2.sentence-3)
[*Example [2](#dcl.typedef-example-2)*: using handler_t = void (*)(int);extern handler_t ignore;extern void (*ignore)(int); // redeclare ignoretemplate<class T> struct P { };using cell = P<cell*>; // error: cell not found ([[basic.scope.pdecl]](basic.scope.pdecl "6.4.2Point of declaration")) — *end example*]
The [*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1General[dcl.type.general]") of the [*defining-type-id*](dcl.name#nt:defining-type-id "9.3.2Type names[dcl.name]") shall not define
a class or enumeration if the [*alias-declaration*](dcl.pre#nt:alias-declaration "9.1Preamble[dcl.pre]") is the [*declaration*](dcl.pre#nt:declaration "9.1Preamble[dcl.pre]") of a [*template-declaration*](temp.pre#nt:template-declaration "13.1Preamble[temp.pre]")[.](#dcl.typedef-2.sentence-4)
[3](#dcl.typedef-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L808)
A [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") is only a [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") if its [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") names
an alias template or a type template template parameter[.](#dcl.typedef-3.sentence-1)
[*Note [1](#dcl.typedef-note-1)*:
A [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") that names a class template specialization
is a [*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") ([[class.name]](class.name "11.3Class names"))[.](#dcl.typedef-3.sentence-2)
If a [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") is used to identify the subject of an[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") ([[dcl.type.elab]](#dcl.type.elab "9.2.9.5Elaborated type specifiers")), a [class
definition](class "11Classes[class]"), a [constructor
declaration](class.ctor "11.4.5Constructors[class.ctor]"), or a [destructor
declaration](class.dtor "11.4.7Destructors[class.dtor]"), the program is ill-formed[.](#dcl.typedef-3.sentence-3)
— *end note*]
[*Example [3](#dcl.typedef-example-3)*: struct S { S(); ~S();};
typedef struct S T;
S a = T(); // OKstruct T * p; // error — *end example*]
[4](#dcl.typedef-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L836)
An unnamed class or enumeration C defined in a typedef declaration has
the first [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") declared by the declaration to be of type C as its [*typedef name for linkage purposes*](#def:typedef_name_for_linkage_purposes "9.2.4The typedef specifier[dcl.typedef]") ([[basic.link]](basic.link "6.7Program and linkage"))[.](#dcl.typedef-4.sentence-1)
[*Note [2](#dcl.typedef-note-2)*:
A typedef declaration involving a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]") does not itself define the associated closure type,
and so the closure type is not given a typedef name for linkage purposes[.](#dcl.typedef-4.sentence-2)
— *end note*]
[*Example [4](#dcl.typedef-example-4)*: typedef struct { } *ps, S; // S is the typedef name for linkage purposestypedef decltype([]{}) C; // the closure type has no typedef name for linkage purposes — *end example*]
[5](#dcl.typedef-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L856)
An unnamed class with a typedef name for linkage purposes shall not
- [(5.1)](#dcl.typedef-5.1)
declare any members
other than non-static data members, member enumerations, or member classes,
- [(5.2)](#dcl.typedef-5.2)
have any base classes or default member initializers, or
- [(5.3)](#dcl.typedef-5.3)
contain a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"),
and all member classes shall also satisfy these requirements (recursively)[.](#dcl.typedef-5.sentence-1)
[*Example [5](#dcl.typedef-example-5)*: typedef struct {int f() {}} X; // error: struct with typedef name for linkage has member functions — *end example*]
### [9.2.5](#dcl.friend) The friend specifier [[dcl.friend]](dcl.friend)
[1](#dcl.friend-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L879)
The friend specifier is used to specify access to class members;
see [[class.friend]](class.friend "11.8.4Friends")[.](#dcl.friend-1.sentence-1)
### [9.2.6](#dcl.constexpr) The constexpr and consteval specifiers [[dcl.constexpr]](dcl.constexpr)
[1](#dcl.constexpr-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L887)
The constexpr specifier shall be applied only to
the definition of a variable or variable template,
a structured binding declaration, or
the declaration of a function or function template[.](#dcl.constexpr-1.sentence-1)
The consteval specifier shall be applied only to
the declaration of a function or function template[.](#dcl.constexpr-1.sentence-2)
A function or static data member
declared with the constexpr or consteval specifier
on its first declaration
is implicitly an inline function or variable ([[dcl.inline]](#dcl.inline "9.2.8The inline specifier"))[.](#dcl.constexpr-1.sentence-3)
If any declaration of a function or function template has
a constexpr or consteval specifier,
then all its declarations shall contain the same specifier[.](#dcl.constexpr-1.sentence-4)
[*Note [1](#dcl.constexpr-note-1)*:
An explicit specialization can differ from the template declaration
with respect to the constexpr or consteval specifier[.](#dcl.constexpr-1.sentence-5)
— *end note*]
[*Note [2](#dcl.constexpr-note-2)*:
Function parameters cannot be declared constexpr[.](#dcl.constexpr-1.sentence-6)
— *end note*]
[*Example [1](#dcl.constexpr-example-1)*: constexpr void square(int &x); // OK, declarationconstexpr int bufsz = 1024; // OK, definitionconstexpr struct pixel { // error: pixel is a typeint x; int y; constexpr pixel(int); // OK, declaration};constexpr pixel::pixel(int a): x(a), y(x) // OK, definition{ square(x); }constexpr pixel small(2); // error: square not defined, so small(2)// not constant ([[expr.const]](expr.const "7.7Constant expressions")) so constexpr not satisfiedconstexpr void square(int &x) { // OK, definition x *= x;}constexpr pixel large(4); // OK, square definedint next(constexpr int x) { // error: not for parametersreturn x + 1;}extern constexpr int memsz; // error: not a definition — *end example*]
[2](#dcl.constexpr-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L934)
A constexpr or consteval specifier
used in the declaration of a function
declares that function to be
a [*constexpr function*](#def:specifier,constexpr,function "9.2.6The constexpr and consteval specifiers[dcl.constexpr]")[.](#dcl.constexpr-2.sentence-1)
[*Note [3](#dcl.constexpr-note-3)*:
A function or constructor declared with the consteval specifier
is an immediate function ([[expr.const]](expr.const "7.7Constant expressions"))[.](#dcl.constexpr-2.sentence-2)
— *end note*]
A destructor, an allocation function, or a deallocation function
shall not be declared with the consteval specifier[.](#dcl.constexpr-2.sentence-3)
[3](#dcl.constexpr-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L946)
A function is [*constexpr-suitable*](#def:constexpr-suitable "9.2.6The constexpr and consteval specifiers[dcl.constexpr]") if
it is not a coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4Coroutine definitions"))[.](#dcl.constexpr-3.sentence-1)
Except for instantiated constexpr functions,
non-templated constexpr functions shall be constexpr-suitable[.](#dcl.constexpr-3.sentence-2)
[*Example [2](#dcl.constexpr-example-2)*: constexpr int square(int x){ return x * x; } // OKconstexpr long long_max(){ return 2147483647; } // OKconstexpr int abs(int x) {if (x < 0) x = -x; return x; // OK}constexpr int constant_non_42(int n) { // OKif (n == 42) {static int value = n; return value; }return n;}constexpr int uninit() {struct { int a; } s; return s.a; // error: uninitialized read of s.a}constexpr int prev(int x){ return --x; } // OKconstexpr int g(int x, int n) { // OKint r = 1; while (--n > 0) r *= x; return r;} — *end example*]
[4](#dcl.constexpr-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L987)
An invocation of a constexpr function in a given context
produces the same result as
an invocation of an equivalent non-constexpr function in the same context
in all respects except that
- [(4.1)](#dcl.constexpr-4.1)
an invocation of a constexpr function
can appear in a constant expression ([[expr.const]](expr.const "7.7Constant expressions")) and
- [(4.2)](#dcl.constexpr-4.2)
copy elision is not performed in a constant expression ([[class.copy.elision]](class.copy.elision "11.9.6Copy/move elision"))[.](#dcl.constexpr-4.sentence-1)
[*Note [4](#dcl.constexpr-note-4)*:
Declaring a function constexpr can change whether an expression
is a constant expression[.](#dcl.constexpr-4.sentence-2)
This can indirectly cause calls to std::is_constant_evaluated within an invocation of the function to produce a different value[.](#dcl.constexpr-4.sentence-3)
— *end note*]
[*Note [5](#dcl.constexpr-note-5)*:
It is possible to write a constexpr function for which
no invocation satisfies the requirements of a core constant expression[.](#dcl.constexpr-4.sentence-4)
— *end note*]
[5](#dcl.constexpr-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1010)
The constexpr and consteval specifiers have no
effect on the type of a constexpr function[.](#dcl.constexpr-5.sentence-1)
[*Example [3](#dcl.constexpr-example-3)*: constexpr int bar(int x, int y) // OK{ return x + y + x*y; }// ...int bar(int x, int y) // error: redefinition of bar{ return x * 2 + 3 * y; } — *end example*]
[6](#dcl.constexpr-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1023)
A constexpr specifier used in an object declaration
declares the object as const[.](#dcl.constexpr-6.sentence-1)
Such an object
shall have literal type and
shall be initialized[.](#dcl.constexpr-6.sentence-2)
A constexpr variable shall be constant-initializable ([[expr.const]](expr.const "7.7Constant expressions"))[.](#dcl.constexpr-6.sentence-3)
A constexpr variable that is an object,
as well as any temporary to which a constexpr reference is bound,
shall have constant destruction[.](#dcl.constexpr-6.sentence-4)
[*Example [4](#dcl.constexpr-example-4)*: struct pixel {int x, y;};constexpr pixel ur = { 1294, 1024 }; // OKconstexpr pixel origin; // error: initializer missingnamespace N {void f() {int x; constexpr int& ar = x; // OKstatic constexpr int& sr = x; // error: x is not constexpr-representable// at the point indicated below}// immediate scope here is that of N} — *end example*]
### [9.2.7](#dcl.constinit) The constinit specifier [[dcl.constinit]](dcl.constinit)
[1](#dcl.constinit-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1056)
The constinit specifier shall be applied only
to a declaration of a variable with static or thread storage duration
or to a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations"))[.](#dcl.constinit-1.sentence-1)
[*Note [1](#dcl.constinit-note-1)*:
A structured binding declaration introduces a uniquely named variable,
to which the constinit specifier applies[.](#dcl.constinit-1.sentence-2)
— *end note*]
If the specifier is applied to any declaration of a variable,
it shall be applied to the initializing declaration[.](#dcl.constinit-1.sentence-3)
No diagnostic is required if no constinit declaration
is reachable at the point of the initializing declaration[.](#dcl.constinit-1.sentence-4)
[2](#dcl.constinit-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1069)
If a variable declared with the constinit specifier has
dynamic initialization ([[basic.start.dynamic]](basic.start.dynamic "6.10.3.3Dynamic initialization of non-block variables")), the program is ill-formed,
even if the implementation would perform that initialization as
a static initialization ([[basic.start.static]](basic.start.static "6.10.3.2Static initialization"))[.](#dcl.constinit-2.sentence-1)
[*Note [2](#dcl.constinit-note-2)*:
The constinit specifier ensures that the variable
is initialized during static initialization[.](#dcl.constinit-2.sentence-2)
— *end note*]
[3](#dcl.constinit-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1079)
[*Example [1](#dcl.constinit-example-1)*: const char * g() { return "dynamic initialization"; }constexpr const char * f(bool p) { return p ? "constant initializer" : g(); }constinit const char * c = f(true); // OKconstinit const char * d = f(false); // error — *end example*]
### [9.2.8](#dcl.inline) The inline specifier [[dcl.inline]](dcl.inline)
[1](#dcl.inline-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1092)
The inline specifier shall be applied only to the declaration
of a variable or function[.](#dcl.inline-1.sentence-1)
[2](#dcl.inline-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1096)
A function declaration ([[dcl.fct]](dcl.fct "9.3.4.6Functions"), [[class.mfct]](class.mfct "11.4.2Member functions"), [[class.friend]](class.friend "11.8.4Friends"))
with an inline specifier declares an[*inline function*](#def:function,inline "9.2.8The inline specifier[dcl.inline]")[.](#dcl.inline-2.sentence-1)
The inline specifier indicates to
the implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism[.](#dcl.inline-2.sentence-2)
An implementation is not required to perform this inline substitution at
the point of call; however, even if this inline substitution is omitted,
the other rules for inline functions specified in this subclause shall
still be respected[.](#dcl.inline-2.sentence-3)
[*Note [1](#dcl.inline-note-1)*:
The inline keyword has no effect on the linkage of a function[.](#dcl.inline-2.sentence-4)
In certain cases, an inline function cannot use names with internal linkage;
see [[basic.link]](basic.link "6.7Program and linkage")[.](#dcl.inline-2.sentence-5)
— *end note*]
[3](#dcl.inline-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1114)
A variable declaration with an inline specifier declares an[*inline variable*](#def:variable,inline "9.2.8The inline specifier[dcl.inline]")[.](#dcl.inline-3.sentence-1)
[4](#dcl.inline-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1118)
The inline specifier shall not appear on a block scope declaration or
on the declaration of a function parameter[.](#dcl.inline-4.sentence-1)
If the inline specifier is used in a friend function declaration, that
declaration shall be a definition or the function shall have previously
been declared inline[.](#dcl.inline-4.sentence-2)
[5](#dcl.inline-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1125)
If a definition of a function or variable is reachable
at the point of its
first declaration as inline, the program is ill-formed[.](#dcl.inline-5.sentence-1)
If a function or variable
with external or module linkage
is declared inline in one definition domain,
an inline declaration of it shall be reachable
from the end of every definition domain in which it is declared;
no diagnostic is required[.](#dcl.inline-5.sentence-2)
[*Note [2](#dcl.inline-note-2)*:
A call to an inline function or a use of an inline variable can be encountered
before its definition becomes reachable in a translation unit[.](#dcl.inline-5.sentence-3)
— *end note*]
[6](#dcl.inline-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1139)
[*Note [3](#dcl.inline-note-3)*:
An inline function or variable
with external or module linkage
can be defined in multiple translation units ([[basic.def.odr]](basic.def.odr "6.3One-definition rule")),
but is one entity with one address[.](#dcl.inline-6.sentence-1)
A type or static variable
defined in the body of such a function
is therefore a single entity[.](#dcl.inline-6.sentence-2)
— *end note*]
[7](#dcl.inline-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1150)
If an inline function or variable that is attached to a named module
is declared in a definition domain,
it shall be defined in that domain[.](#dcl.inline-7.sentence-1)
[*Note [4](#dcl.inline-note-4)*:
A [constexpr function](#def:specifier,constexpr,function "9.2.6The constexpr and consteval specifiers[dcl.constexpr]") is implicitly inline[.](#dcl.inline-7.sentence-2)
In the global module, a function defined within a class definition
is implicitly inline ([[class.mfct]](class.mfct "11.4.2Member functions"), [[class.friend]](class.friend "11.8.4Friends"))[.](#dcl.inline-7.sentence-3)
— *end note*]
### [9.2.9](#dcl.type) Type specifiers [[dcl.type]](dcl.type)
#### [9.2.9.1](#dcl.type.general) General [[dcl.type.general]](dcl.type.general)
[1](#dcl.type.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1165)
The type-specifiers are
[type-specifier:](#nt:type-specifier "9.2.9.1General[dcl.type.general]")
[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")
[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]")
[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1General[temp.res.general]")
[*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]")
[type-specifier-seq:](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]")
[*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt
[*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]")
[defining-type-specifier:](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]")
[*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]")
[*class-specifier*](class.pre#nt:class-specifier "11.1Preamble[class.pre]")
[*enum-specifier*](dcl.enum#nt:enum-specifier "9.8.1Enumeration declarations[dcl.enum]")
[defining-type-specifier-seq:](#nt:defining-type-specifier-seq "9.2.9.1General[dcl.type.general]")
[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt
[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]") [*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1General[dcl.type.general]")
The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") in a [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") or a [*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1General[dcl.type.general]") appertains
to the type denoted by the preceding [*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* or [*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]")*s* ([[dcl.meaning]](dcl.meaning "9.3.4Meaning of declarators"))[.](#dcl.type.general-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[.](#dcl.type.general-1.sentence-3)
[2](#dcl.type.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1205)
As a general rule, at most one[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]") is allowed in the complete[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") of a [*declaration*](dcl.pre#nt:declaration "9.1Preamble[dcl.pre]") or in a[*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1General[dcl.type.general]"),
and at most one[*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") is allowed in a[*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]")[.](#dcl.type.general-2.sentence-1)
The only exceptions to this rule are the following:
- [(2.1)](#dcl.type.general-2.1)
const can be combined with any type specifier except itself[.](#dcl.type.general-2.1.sentence-1)
- [(2.2)](#dcl.type.general-2.2)
volatile can be combined with any type specifier except itself[.](#dcl.type.general-2.2.sentence-1)
- [(2.3)](#dcl.type.general-2.3)
signed or unsigned can be combined withchar, long, short, or int[.](#dcl.type.general-2.3.sentence-1)
- [(2.4)](#dcl.type.general-2.4)
short or long can be combined with int[.](#dcl.type.general-2.4.sentence-1)
- [(2.5)](#dcl.type.general-2.5)
long can be combined with double[.](#dcl.type.general-2.5.sentence-1)
- [(2.6)](#dcl.type.general-2.6)
long can be combined with long[.](#dcl.type.general-2.6.sentence-1)
[3](#dcl.type.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1231)
Except in a declaration of a constructor, destructor, or conversion
function, at least one [*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1General[dcl.type.general]") that is not a[*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]") shall appear in a complete[*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") or a complete[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]")[.](#dcl.type.general-3.sentence-1)[74](#footnote-74 "There is no special provision for a decl-specifier-seq that lacks a type-specifier or that has a type-specifier that only specifies cv-qualifiers. The “implicit int” rule of C is no longer supported.")
[4](#dcl.type.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1245)
[*Note [1](#dcl.type.general-note-1)*:
[*enum-specifier*](dcl.enum#nt:enum-specifier "9.8.1Enumeration declarations[dcl.enum]")*s*,[*class-specifier*](class.pre#nt:class-specifier "11.1Preamble[class.pre]")*s*,
and[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1General[temp.res.general]")*s* are discussed
in[[dcl.enum]](dcl.enum "9.8.1Enumeration declarations"),[[class]](class "11Classes"),
and[[temp.res]](temp.res "13.8Name resolution"), respectively[.](#dcl.type.general-4.sentence-1)
The remaining[*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* are discussed in the rest of [[dcl.type]](#dcl.type "9.2.9Type specifiers")[.](#dcl.type.general-4.sentence-2)
— *end note*]
[74)](#footnote-74)[74)](#footnoteref-74)
There is no special
provision for a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") that
lacks a [*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") or that has a[*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") that only specifies [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]")*s*[.](#footnote-74.sentence-1)
The “implicit int” rule of C is no longer supported[.](#footnote-74.sentence-2)
#### [9.2.9.2](#dcl.type.cv) The *cv-qualifier**s* [[dcl.type.cv]](dcl.type.cv)
[1](#dcl.type.cv-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1266)
There are two [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]")*s*, const andvolatile[.](#dcl.type.cv-1.sentence-1)
Each [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]") shall appear at most once in
a [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1General[dcl.decl.general]")[.](#dcl.type.cv-1.sentence-2)
If a [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1General[dcl.decl.general]") appears in a[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]"), the [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1General[dcl.decl.general]") or [*member-declarator-list*](class.mem.general#nt:member-declarator-list "11.4.1General[class.mem.general]") of
the declaration shall not be empty[.](#dcl.type.cv-1.sentence-3)
[*Note [1](#dcl.type.cv-note-1)*:
[[basic.type.qualifier]](basic.type.qualifier "6.9.5CV-qualifiers") and [[dcl.fct]](dcl.fct "9.3.4.6Functions") describe how cv-qualifiers affect object and
function types[.](#dcl.type.cv-1.sentence-4)
— *end note*]
Redundant cv-qualifications are ignored[.](#dcl.type.cv-1.sentence-5)
[*Note [2](#dcl.type.cv-note-2)*:
For example,
these could be introduced by typedefs[.](#dcl.type.cv-1.sentence-6)
— *end note*]
[2](#dcl.type.cv-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1283)
[*Note [3](#dcl.type.cv-note-3)*:
Declaring a variable const can affect its linkage ([[dcl.stc]](#dcl.stc "9.2.2Storage class specifiers"))
and its usability in constant expressions ([[expr.const]](expr.const "7.7Constant expressions"))[.](#dcl.type.cv-2.sentence-1)
As
described in [[dcl.init]](dcl.init "9.5Initializers"), the definition of an object or subobject
of const-qualified type must specify an initializer or be subject to
default-initialization[.](#dcl.type.cv-2.sentence-2)
— *end note*]
[3](#dcl.type.cv-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1292)
A pointer or reference to a cv-qualified type need not actually point or
refer to a cv-qualified object, but it is treated as if it does; a
const-qualified access path cannot be used to modify an object even if
the object referenced is a non-const object and can be modified through
some other access path[.](#dcl.type.cv-3.sentence-1)
[*Note [4](#dcl.type.cv-note-4)*:
Cv-qualifiers are supported by the type system so that they cannot be
subverted without [casting](expr.const.cast "7.6.1.11Const cast[expr.const.cast]")[.](#dcl.type.cv-3.sentence-2)
— *end note*]
[4](#dcl.type.cv-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1303)
Any attempt to modify ([[expr.assign]](expr.assign "7.6.19Assignment and compound assignment operators"), [[expr.post.incr]](expr.post.incr "7.6.1.6Increment and decrement"), [[expr.pre.incr]](expr.pre.incr "7.6.2.3Increment and decrement")) a
const object ([[basic.type.qualifier]](basic.type.qualifier "6.9.5CV-qualifiers")) during its
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) results in undefined behavior[.](#dcl.type.cv-4.sentence-1)
[*Example [1](#dcl.type.cv-example-1)*: const int ci = 3; // cv-qualified (initialized as required) ci = 4; // error: attempt to modify constint i = 2; // not cv-qualifiedconst int* cip; // pointer to const int cip = &i; // OK, cv-qualified access path to unqualified*cip = 4; // error: attempt to modify through ptr to constint* ip;
ip = const_cast<int*>(cip); // cast needed to convert const int* to int**ip = 4; // defined: *ip points to i, a non-const objectconst int* ciq = new const int (3); // initialized as requiredint* iq = const_cast<int*>(ciq); // cast required*iq = 4; // undefined behavior: modifies a const object
For another example,struct X {mutable int i; int j;};struct Y { X x;
Y();};
const Y y;
y.x.i++; // well-formed: mutable member can be modified y.x.j++; // error: const-qualified member modified Y* p = const_cast<Y*>(&y); // cast away const-ness of y p->x.i = 99; // well-formed: mutable member can be modified p->x.j = 99; // undefined behavior: modifies a const subobject
— *end example*]
[5](#dcl.type.cv-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1346)
The semantics of an access through a volatile glvalue areimplementation-defined[.](#dcl.type.cv-5.sentence-1)
If an attempt is made to access an object defined with a
volatile-qualified type through the use of a non-volatile glvalue,
the behavior is undefined[.](#dcl.type.cv-5.sentence-2)
[6](#dcl.type.cv-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1353)
[*Note [5](#dcl.type.cv-note-5)*:
volatile is a hint to the implementation to avoid aggressive
optimization involving the object because it is possible for the value of the object
to change by means undetectable by an implementation[.](#dcl.type.cv-6.sentence-1)
Furthermore, for some implementations, volatile can indicate that
special hardware instructions are needed to access the object[.](#dcl.type.cv-6.sentence-2)
See [[intro.execution]](intro.execution "6.10.1Sequential execution") for detailed semantics[.](#dcl.type.cv-6.sentence-3)
In general, the
semantics of volatile are intended to be the same in C++ as
they are in C[.](#dcl.type.cv-6.sentence-4)
— *end note*]
#### [9.2.9.3](#dcl.type.simple) Simple type specifiers [[dcl.type.simple]](dcl.type.simple)
[1](#dcl.type.simple-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1370)
The simple type specifiers are
[simple-type-specifier:](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*type-name*](#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]")
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") template [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
[*computed-type-specifier*](#nt:computed-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")
[*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]")
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]")
char
char8_t
char16_t
char32_t
wchar_t
bool
short
int
long
signed
unsigned
float
double
void
[type-name:](#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]")
[*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]")
[*enum-name*](dcl.enum#nt:enum-name "9.8.1Enumeration declarations[dcl.enum]")
[*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]")
[computed-type-specifier:](#nt:computed-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")
[*decltype-specifier*](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]")
[*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]")
[*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]")
[2](#dcl.type.simple-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1409)
The component names of a [*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]") are those of its[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]"),[*type-name*](#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]"),[*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]"),[*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]"), and/or[*type-constraint*](temp.param#nt:type-constraint "13.2Template parameters[temp.param]") (if it is a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]"))[.](#dcl.type.simple-2.sentence-1)
The component name of a [*type-name*](#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]") is the first name in it[.](#dcl.type.simple-2.sentence-2)
[3](#dcl.type.simple-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1420)
A [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") is a placeholder for
a type to be deduced ([[dcl.spec.auto]](#auto "9.2.9.7Placeholder type specifiers"))[.](#dcl.type.simple-3.sentence-1)
A [*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") is a placeholder for
a deduced class type ([[dcl.type.class.deduct]](#dcl.type.class.deduct "9.2.9.8Deduced class template specialization types")) if either
- [(3.1)](#dcl.type.simple-3.1)
it is of the formtypenameopt [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") or
- [(3.2)](#dcl.type.simple-3.2)
it is of the form typenameopt [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") and
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") designates
a class template or alias template[.](#dcl.type.simple-3.sentence-2)
The [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") or [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]"),
if any, shall be non-dependent and
the [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") or [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") shall designate a deducible template[.](#dcl.type.simple-3.sentence-3)
A [*deducible template*](#def:template,deducible "9.2.9.3Simple type specifiers[dcl.type.simple]") is either a class template or
is an alias template whose [*defining-type-id*](dcl.name#nt:defining-type-id "9.3.2Type names[dcl.name]") is of the form
typenameopt [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
where the [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") (if any) is non-dependent and
the [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") of the [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") names a deducible template[.](#dcl.type.simple-3.sentence-5)
[*Note [1](#dcl.type.simple-note-1)*:
An injected-class-name is never interpreted as a [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") in contexts where class template argument deduction would be performed ([[temp.local]](temp.local "13.8.2Locally declared names"))[.](#dcl.type.simple-3.sentence-6)
— *end note*]
The other[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")*s* specify either a previously-declared type, a type determined from an
expression, or one of the
fundamental types ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental types"))[.](#dcl.type.simple-3.sentence-7)
Table [17](#tab:dcl.type.simple "Table 17: simple-type-specifiers and the types they specify") summarizes the valid combinations of[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")*s* and the types they specify[.](#dcl.type.simple-3.sentence-8)
Table [17](#tab:dcl.type.simple) — [*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")*s* and the types they specify [[tab:dcl.type.simple]](./tab:dcl.type.simple)
| [🔗](#tab:dcl.type.simple-row-1)<br>**Specifier(s)** | **Type** |
| --- | --- |
| [🔗](#tab:dcl.type.simple-row-2)<br>[*type-name*](#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]") | the type named |
| [🔗](#tab:dcl.type.simple-row-3)<br>[*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") | the type as defined in [[temp.names]](temp.names "13.3Names of template specializations") |
| [🔗](#tab:dcl.type.simple-row-4)<br>[*decltype-specifier*](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]") | the type as defined in [[dcl.type.decltype]](#dcl.type.decltype "9.2.9.6Decltype specifiers") |
| [🔗](#tab:dcl.type.simple-row-5)<br>[*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]") | the type as defined in [[dcl.type.pack.index]](#dcl.type.pack.index "9.2.9.4Pack indexing specifier") |
| [🔗](#tab:dcl.type.simple-row-6)<br>[*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1General[dcl.spec.auto.general]") | the type as defined in [[dcl.spec.auto]](#auto "9.2.9.7Placeholder type specifiers") |
| [🔗](#tab:dcl.type.simple-row-7)<br>[*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") | the type as defined in [[dcl.type.class.deduct]](#dcl.type.class.deduct "9.2.9.8Deduced class template specialization types") |
| [🔗](#tab:dcl.type.simple-row-8)<br>[*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]") | the type as defined in [[dcl.type.splice]](#dcl.type.splice "9.2.9.9Type splicing") |
| [🔗](#tab:dcl.type.simple-row-9)<br>char | “char” |
| [🔗](#tab:dcl.type.simple-row-10)<br>unsigned char | “unsigned char” |
| [🔗](#tab:dcl.type.simple-row-11)<br>signed char | “signed char” |
| [🔗](#tab:dcl.type.simple-row-12)<br>char8_t | “char8_t” |
| [🔗](#tab:dcl.type.simple-row-13)<br>char16_t | “char16_t” |
| [🔗](#tab:dcl.type.simple-row-14)<br>char32_t | “char32_t” |
| [🔗](#tab:dcl.type.simple-row-15)<br>bool | “bool” |
| [🔗](#tab:dcl.type.simple-row-16)<br>unsigned | “unsigned int” |
| [🔗](#tab:dcl.type.simple-row-17)<br>unsigned int | “unsigned int” |
| [🔗](#tab:dcl.type.simple-row-18)<br>signed | “int” |
| [🔗](#tab:dcl.type.simple-row-19)<br>signed int | “int” |
| [🔗](#tab:dcl.type.simple-row-20)<br>int | “int” |
| [🔗](#tab:dcl.type.simple-row-21)<br>unsigned short int | “unsigned short int” |
| [🔗](#tab:dcl.type.simple-row-22)<br>unsigned short | “unsigned short int” |
| [🔗](#tab:dcl.type.simple-row-23)<br>unsigned long int | “unsigned long int” |
| [🔗](#tab:dcl.type.simple-row-24)<br>unsigned long | “unsigned long int” |
| [🔗](#tab:dcl.type.simple-row-25)<br>unsigned long long int | “unsigned long long int” |
| [🔗](#tab:dcl.type.simple-row-26)<br>unsigned long long | “unsigned long long int” |
| [🔗](#tab:dcl.type.simple-row-27)<br>signed long int | “long int” |
| [🔗](#tab:dcl.type.simple-row-28)<br>signed long | “long int” |
| [🔗](#tab:dcl.type.simple-row-29)<br>signed long long int | “long long int” |
| [🔗](#tab:dcl.type.simple-row-30)<br>signed long long | “long long int” |
| [🔗](#tab:dcl.type.simple-row-31)<br>long long int | “long long int” |
| [🔗](#tab:dcl.type.simple-row-32)<br>long long | “long long int” |
| [🔗](#tab:dcl.type.simple-row-33)<br>long int | “long int” |
| [🔗](#tab:dcl.type.simple-row-34)<br>long | “long int” |
| [🔗](#tab:dcl.type.simple-row-35)<br>signed short int | “short int” |
| [🔗](#tab:dcl.type.simple-row-36)<br>signed short | “short int” |
| [🔗](#tab:dcl.type.simple-row-37)<br>short int | “short int” |
| [🔗](#tab:dcl.type.simple-row-38)<br>short | “short int” |
| [🔗](#tab:dcl.type.simple-row-39)<br>wchar_t | “wchar_t” |
| [🔗](#tab:dcl.type.simple-row-40)<br>float | “float” |
| [🔗](#tab:dcl.type.simple-row-41)<br>double | “double” |
| [🔗](#tab:dcl.type.simple-row-42)<br>long double | “long double” |
| [🔗](#tab:dcl.type.simple-row-43)<br>void | “void” |
[4](#dcl.type.simple-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1531)
When multiple [*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]")*s* are allowed, they can be
freely intermixed with other [*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in any order[.](#dcl.type.simple-4.sentence-1)
[*Note [2](#dcl.type.simple-note-2)*:
It is implementation-defined whether objects of char type are
represented as signed or unsigned quantities[.](#dcl.type.simple-4.sentence-2)
The signed specifier
forces char objects to be signed; it is redundant in other contexts[.](#dcl.type.simple-4.sentence-3)
— *end note*]
#### [9.2.9.4](#dcl.type.pack.index) Pack indexing specifier [[dcl.type.pack.index]](dcl.type.pack.index)
[pack-index-specifier:](#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]")
[*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") ... [ [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") ]
[1](#dcl.type.pack.index-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1547)
The [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") P in a [*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]") shall denote a pack[.](#dcl.type.pack.index-1.sentence-1)
[2](#dcl.type.pack.index-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1551)
The [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") shall be
a converted constant expression ([[expr.const]](expr.const "7.7Constant expressions")) of type std::size_t whose value V, termed the index,
is such that 0≤V<sizeof...(P)[.](#dcl.type.pack.index-2.sentence-1)
[3](#dcl.type.pack.index-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1557)
A [*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]") is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4Variadic templates"))[.](#dcl.type.pack.index-3.sentence-1)
[4](#dcl.type.pack.index-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1560)
[*Note [1](#dcl.type.pack.index-note-1)*:
The [*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]") denotes
the type of the Vth element of the pack[.](#dcl.type.pack.index-4.sentence-1)
— *end note*]
#### [9.2.9.5](#dcl.type.elab) Elaborated type specifiers [[dcl.type.elab]](dcl.type.elab)
[elaborated-type-specifier:](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]")
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
enum [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")
[1](#dcl.type.elab-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1579)
The component names of an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") are
its [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") (if any) and
those of its [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") and[*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") (if any)[.](#dcl.type.elab-1.sentence-1)
[2](#dcl.type.elab-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1586)
If an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") is the sole constituent of a
declaration, the declaration is ill-formed unless it is an explicit
specialization ([[temp.expl.spec]](temp.expl.spec "13.9.4Explicit specialization")),
a partial specialization ([[temp.spec.partial]](temp.spec.partial "13.7.6Partial specialization")),
an explicit
instantiation ([[temp.explicit]](temp.explicit "13.9.3Explicit instantiation")), or it has one of the following
forms:
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") ;
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") ;
In the first case,
the [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") declares
the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") as a [*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]")[.](#dcl.type.elab-2.sentence-2)
The second case shall appear only
in an [*explicit-specialization*](temp.expl.spec#nt:explicit-specialization "13.9.4Explicit specialization[temp.expl.spec]") ([[temp.expl.spec]](temp.expl.spec "13.9.4Explicit specialization")) or
in a [*template-declaration*](temp.pre#nt:template-declaration "13.1Preamble[temp.pre]") (where it declares a partial specialization)[.](#dcl.type.elab-2.sentence-3)
The [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]"), if any, appertains
to the class or template being declared[.](#dcl.type.elab-2.sentence-4)
[3](#dcl.type.elab-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1611)
Otherwise, an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") E shall not have
an [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")[.](#dcl.type.elab-3.sentence-1)
If E contains an [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") but no [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") and
(unqualified) lookup for the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") finds nothing,E shall not be introduced by the enum keyword and
declares the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") as a [*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]")[.](#dcl.type.elab-3.sentence-2)
The target scope of E is the nearest enclosing namespace or block scope[.](#dcl.type.elab-3.sentence-3)
[4](#dcl.type.elab-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1621)
A [*friend-type-specifier*](class.mem.general#nt:friend-type-specifier "11.4.1General[class.mem.general]") that is an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") shall have one of the following forms:
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]")
Any unqualified lookup for the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") (in the first case)
does not consider scopes that contain
the nearest enclosing namespace or block scope; no name is bound[.](#dcl.type.elab-4.sentence-1)
[*Note [1](#dcl.type.elab-note-1)*:
A [*using-directive*](namespace.udir#nt:using-directive "9.9.4Using namespace directive[namespace.udir]") in the target scope is ignored
if it refers to a namespace not contained by that scope[.](#dcl.type.elab-4.sentence-2)
— *end note*]
[5](#dcl.type.elab-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1638)
[*Note [2](#dcl.type.elab-note-2)*:
[[basic.lookup.elab]](basic.lookup.elab "6.5.6Elaborated type specifiers") describes how name lookup proceeds
in an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]")[.](#dcl.type.elab-5.sentence-1)
An [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") can be used to refer to
a previously declared [*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") or [*enum-name*](dcl.enum#nt:enum-name "9.8.1Enumeration declarations[dcl.enum]") even if the name has been hidden by a non-type declaration[.](#dcl.type.elab-5.sentence-2)
— *end note*]
[6](#dcl.type.elab-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1647)
If the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") or [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") in an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") resolves to a [*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") or[*enum-name*](dcl.enum#nt:enum-name "9.8.1Enumeration declarations[dcl.enum]"), the [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") introduces it into the declaration the same way a[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]") introduces
its [*type-name*](#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]") ([[dcl.type.simple]](#dcl.type.simple "9.2.9.3Simple type specifiers"))[.](#dcl.type.elab-6.sentence-1)
If the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") or [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") resolves to a[*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") ([[dcl.typedef]](#dcl.typedef "9.2.4The typedef specifier"), [[temp.names]](temp.names "13.3Names of template specializations")),
the [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") is ill-formed[.](#dcl.type.elab-6.sentence-2)
[*Note [3](#dcl.type.elab-note-3)*:
This implies that, within a class template with a template[*type-parameter*](temp.param#nt:type-parameter "13.2Template parameters[temp.param]") T, the declarationfriend class T; is ill-formed[.](#dcl.type.elab-6.sentence-3)
However, the similar declaration friend T; is well-formed ([[class.friend]](class.friend "11.8.4Friends"))[.](#dcl.type.elab-6.sentence-4)
— *end note*]
[7](#dcl.type.elab-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1667)
The [*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") or enum keyword
present in an[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") shall agree in kind with the
declaration to which the name in the[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") refers[.](#dcl.type.elab-7.sentence-1)
This rule also applies to
the form of [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]") that declares a[*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") or friend class since it can be construed
as referring to the definition of the class[.](#dcl.type.elab-7.sentence-2)
Thus, in any[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5Elaborated type specifiers[dcl.type.elab]"), the enum keyword
shall be
used to refer to an enumeration ([[dcl.enum]](dcl.enum "9.8.1Enumeration declarations")), the union[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") shall be used to refer to a union ([[class.union]](class.union "11.5Unions")),
and either the class or struct[*class-key*](class.pre#nt:class-key "11.1Preamble[class.pre]") shall be used to refer to a non-union class ([[class.pre]](class.pre "11.1Preamble"))[.](#dcl.type.elab-7.sentence-3)
[*Example [1](#dcl.type.elab-example-1)*: enum class E { a, b };enum E x = E::a; // OKstruct S { } s;class S* p = &s; // OK — *end example*]
#### [9.2.9.6](#dcl.type.decltype) Decltype specifiers [[dcl.type.decltype]](dcl.type.decltype)
[decltype-specifier:](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]")
decltype ( [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") )
[1](#dcl.type.decltype-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1699)
For an expression E, the type denoted by decltype(E) is defined as follows:
- [(1.1)](#dcl.type.decltype-1.1)
if E is an unparenthesized [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") naming a structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations")),decltype(E) is the referenced type as given in
the specification of the structured binding declaration;
- [(1.2)](#dcl.type.decltype-1.2)
otherwise, if E is an unparenthesized [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") naming a constant template parameter ([[temp.param]](temp.param "13.2Template parameters")),decltype(E) is the type of the template parameter
after performing any necessary
type deduction ([[dcl.spec.auto]](#auto "9.2.9.7Placeholder type specifiers"), [[dcl.type.class.deduct]](#dcl.type.class.deduct "9.2.9.8Deduced class template specialization types"));
- [(1.3)](#dcl.type.decltype-1.3)
otherwise, if E is an unparenthesized [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") or
an unparenthesized
class
member access ([[expr.ref]](expr.ref "7.6.1.5Class member access")), decltype(E) is the
type of the entity named by E[.](#dcl.type.decltype-1.3.sentence-1)
If there is no such entity, the program is ill-formed;
- [(1.4)](#dcl.type.decltype-1.4)
otherwise, if E is an unparenthesized [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9Expression splicing[expr.prim.splice]"),decltype(E) is the type of the entity, object, or value
designated by the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") of E;
- [(1.5)](#dcl.type.decltype-1.5)
otherwise, if E is
an xvalue, decltype(E) is T&&, where T is the type
of E;
- [(1.6)](#dcl.type.decltype-1.6)
otherwise, if E is an lvalue, decltype(E) is T&, where T is the type of E;
- [(1.7)](#dcl.type.decltype-1.7)
otherwise, decltype(E) is the type of E[.](#dcl.type.decltype-1.7.sentence-1)
The operand of the decltype specifier is an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3Context dependence[expr.context]")[.](#dcl.type.decltype-1.sentence-2)
[*Example [1](#dcl.type.decltype-example-1)*: const int&& foo();int i;struct A { double x; };const A* a = new A();decltype(foo()) x1 = 17; // type is const int&&decltype(i) x2; // type is intdecltype(a->x) x3; // type is doubledecltype((a->x)) x4 = x3; // type is const double&decltype([:^^x1:]) x5 = 18; // type is const int&&decltype(([:^^x1:])) x6 = 19; // type is const int&void f() {[](auto ...pack) {decltype(pack...[0]) x7; // type is intdecltype((pack...[0])) x8; // type is int&}(0);} — *end example*]
[*Note [1](#dcl.type.decltype-note-1)*:
The rules for determining types involving decltype(auto) are specified
in [[dcl.spec.auto]](#auto "9.2.9.7Placeholder type specifiers")[.](#dcl.type.decltype-1.sentence-3)
— *end note*]
[2](#dcl.type.decltype-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1763)
If the operand of a [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]") is a prvalue
and is not a (possibly parenthesized) immediate invocation ([[expr.const]](expr.const "7.7Constant expressions")),
the temporary materialization conversion is not applied ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion"))
and no result object is provided for the prvalue[.](#dcl.type.decltype-2.sentence-1)
The type of the prvalue may be incomplete or an abstract class type[.](#dcl.type.decltype-2.sentence-2)
[*Note [2](#dcl.type.decltype-note-2)*:
As a result, storage is not allocated for the prvalue and it is not destroyed[.](#dcl.type.decltype-2.sentence-3)
Thus, a class type is not instantiated
as a result of being the type of a function call in this context[.](#dcl.type.decltype-2.sentence-4)
In this context, the common purpose of
writing the expression is merely to refer to its type[.](#dcl.type.decltype-2.sentence-5)
In that sense, a[*decltype-specifier*](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]") is analogous to a use of a [*typedef-name*](#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]"),
so the usual reasons for requiring a complete type do not apply[.](#dcl.type.decltype-2.sentence-6)
In particular,
it is not necessary to allocate storage for a temporary object or to enforce the
semantic constraints associated with invoking the type's destructor[.](#dcl.type.decltype-2.sentence-7)
— *end note*]
[*Note [3](#dcl.type.decltype-note-3)*:
Unlike the preceding rule, parentheses have no special meaning in this context[.](#dcl.type.decltype-2.sentence-8)
— *end note*]
[*Example [2](#dcl.type.decltype-example-2)*: template<class T> struct A { ~A() = delete; };template<class T> auto h()-> A<T>;template<class T> auto i(T) // identity-> T;template<class T> auto f(T) // #1-> decltype(i(h<T>())); // forces completion of A<T> and implicitly uses A<T>::~A()// for the temporary introduced by the use of h().// (A temporary is not introduced as a result of the use of i().)template<class T> auto f(T) // #2-> void;auto g() -> void { f(42); // OK, calls #2. (#1 is not a viable candidate: type deduction// fails ([[temp.deduct]](temp.deduct "13.10.3Template argument deduction")) because A<int>::~A() is implicitly used in its// [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]"))}template<class T> auto q(T)-> decltype((h<T>())); // does not force completion of A<T>; A<T>::~A() is not implicitly// used within the context of this [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6Decltype specifiers[dcl.type.decltype]")void r() { q(42); // error: deduction against q succeeds, so overload resolution selects// the specialization “q(T) -> decltype((h<T>()))'' with T=int;// the return type is A<int>, so a temporary is introduced and its// destructor is used, so the program is ill-formed} — *end example*]
#### [9.2.9.7](#auto) Placeholder type specifiers [[dcl.spec.auto]](dcl.spec.auto)
#### [9.2.9.7.1](#auto.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](#auto.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[.](#auto.general-1.sentence-1)
[2](#auto.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)](#auto.general-2.1)
function declaration ([[dcl.fct]](dcl.fct "9.3.4.6Functions")),
- [(2.2)](#auto.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)](#auto.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[.](#auto.general-2.sentence-1)
The placeholder type shall appear
as one of the [*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in
the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or
as one of the [*type-specifier*](#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*](#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[.](#auto.general-2.sentence-2)
[*Note [1](#auto.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"))[.](#auto.general-2.sentence-3)
— *end note*]
[3](#auto.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1861)
A placeholder type can appear in
the [*decl-specifier-seq*](#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"))[.](#auto.general-3.sentence-1)
[4](#auto.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1866)
A placeholder type can appear in
the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or [*type-specifier-seq*](#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"))[.](#auto.general-4.sentence-1)
[5](#auto.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[.](#auto.general-5.sentence-1)
This use is allowed
in an initializing declaration ([[dcl.init]](dcl.init "9.5Initializers")) of a variable[.](#auto.general-5.sentence-2)
The placeholder type shall appear as one of the[*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]")*s* in the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") or as one of the[*type-specifier*](#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*](#nt:decl-specifier "9.2.1General[dcl.spec.general]");
the [*decl-specifier-seq*](#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]")[.](#auto.general-5.sentence-3)
[*Example [1](#auto.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*](#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*](#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"))[.](#auto.general-5.sentence-4)
[6](#auto.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*](#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"))[.](#auto.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*](#nt:type-specifier "9.2.9.1General[dcl.type.general]")*s* in
the [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") or
as one of the [*type-specifier*](#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*](#nt:type-specifier "9.2.9.1General[dcl.type.general]")[.](#auto.general-6.sentence-2)
[7](#auto.general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1920)
The auto [*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") can also be used
as the [*simple-type-specifier*](#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)"))[.](#auto.general-7.sentence-1)
[8](#auto.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]](#auto "9.2.9.7Placeholder type specifiers") is ill-formed[.](#auto.general-8.sentence-1)
[9](#auto.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[.](#auto.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[.](#auto.general-9.sentence-2)
[*Example [2](#auto.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](#auto.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[.](#auto.general-10.sentence-1)
If the type deduced is not the same in each
deduction, the program is ill-formed[.](#auto.general-10.sentence-2)
[11](#auto.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[.](#auto.general-11.sentence-1)
[*Example [3](#auto.general-example-3)*: auto f() { } // OK, return type is voidauto* g() { } // error: cannot deduce auto* from void() — *end example*]
[12](#auto.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)[.](#auto.general-12.sentence-1)
[*Note [2](#auto.general-note-2)*:
The deduced return type cannot have
a name with internal linkage ([[basic.link]](basic.link "6.7Program and linkage"))[.](#auto.general-12.sentence-2)
— *end note*]
[13](#auto.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[.](#auto.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[.](#auto.general-13.sentence-2)
[*Example [4](#auto.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](#auto.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"))[.](#auto.general-14.sentence-1)
[*Example [5](#auto.general-example-5)*: auto f() post(r : r == 7) // OK{return 7;} — *end example*]
[15](#auto.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[.](#auto.general-15.sentence-1)
[*Note [3](#auto.general-note-3)*:
Therefore, any use of a specialization of the function template will
cause an implicit instantiation[.](#auto.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"))[.](#auto.general-15.sentence-3)
— *end note*]
[*Example [6](#auto.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](#auto.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[.](#auto.general-16.sentence-1)
[*Example [7](#auto.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](#auto.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"))[.](#auto.general-17.sentence-1)
[18](#auto.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"))[.](#auto.general-18.sentence-1)
[19](#auto.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[.](#auto.general-19.sentence-1)
[*Example [8](#auto.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)
#### [9.2.9.8](#dcl.type.class.deduct) Deduced class template specialization types [[dcl.type.class.deduct]](dcl.type.class.deduct)
[1](#dcl.type.class.deduct-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2254)
If a placeholder for a deduced class type
appears as a [*decl-specifier*](#nt:decl-specifier "9.2.1General[dcl.spec.general]") in the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") of an initializing declaration ([[dcl.init]](dcl.init "9.5Initializers")) of a variable,
the declared type of the variable shall be cv T,
where T is the placeholder[.](#dcl.type.class.deduct-1.sentence-1)
[*Example [1](#dcl.type.class.deduct-example-1)*: template <class ...T> struct A { A(T...) {}};
A x[29]{}; // error: no declarator operators allowedconst A& y{}; // error: no declarator operators allowed — *end example*]
The placeholder is replaced by the return type
of the function selected by overload resolution
for class template deduction ([[over.match.class.deduct]](over.match.class.deduct "12.2.2.9Class template argument deduction"))[.](#dcl.type.class.deduct-1.sentence-2)
If the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") is followed by an [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1General[dcl.decl.general]") or [*member-declarator-list*](class.mem.general#nt:member-declarator-list "11.4.1General[class.mem.general]") containing more than one [*declarator*](dcl.decl.general#nt:declarator "9.3.1General[dcl.decl.general]"),
the type that replaces the placeholder shall be the same in each deduction[.](#dcl.type.class.deduct-1.sentence-3)
[2](#dcl.type.class.deduct-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2279)
A placeholder for a deduced class type
can also be used
in the [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1General[dcl.type.general]") in the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8New[expr.new]") or [*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")),
as the [*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3Simple type specifiers[dcl.type.simple]") in an [explicit type conversion (functional notation)](expr.type.conv "7.6.1.4Explicit type conversion (functional notation)[expr.type.conv]"),
or
as the [*type-specifier*](#nt:type-specifier "9.2.9.1General[dcl.type.general]") in the [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6Functions[dcl.fct]") of a [*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") ([[temp.param]](temp.param "13.2Template parameters"))[.](#dcl.type.class.deduct-2.sentence-1)
A placeholder for a deduced class type
shall not appear in any other context[.](#dcl.type.class.deduct-2.sentence-2)
[3](#dcl.type.class.deduct-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2293)
[*Example [2](#dcl.type.class.deduct-example-2)*: template<class T> struct container { container(T t) {}template<class Iter> container(Iter beg, Iter end);};template<class Iter> container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
std::vector<double> v = { /* ... */ };
container c(7); // OK, deduces int for Tauto d = container(v.begin(), v.end()); // OK, deduces double for T container e{5, 6}; // error: int is not an iterator — *end example*]
#### [9.2.9.9](#dcl.type.splice) Type splicing [[dcl.type.splice]](dcl.type.splice)
[splice-type-specifier:](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]")
typenameopt [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]")
typenameopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]")
[1](#dcl.type.splice-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2318)
A [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]") immediately followed by :: is never interpreted as part of a [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]")[.](#dcl.type.splice-1.sentence-1)
A [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]") not preceded by typename is only interpreted as a [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]") within a type-only context ([[temp.res.general]](temp.res.general "13.8.1General"))[.](#dcl.type.splice-1.sentence-2)
[*Example [1](#dcl.type.splice-example-1)*: template<std::meta::info R> void tfn() {typename [:R:]::type m; // OK, typename applies to the qualified name}struct S { using type = int; };void fn() {[:^^S::type:] *var; // error: [:^^S::type:] is an expressiontypename [:^^S::type:] *var; // OK, declares variable with type int*}using alias = [:^^S::type:]; // OK, type-only context — *end example*]
[2](#dcl.type.splice-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2344)
For a [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]") of the formtypenameopt [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]"),
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") shall designate
a type, a class template, or an alias template[.](#dcl.type.splice-2.sentence-1)
The [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]") designates
the same entity as the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]")[.](#dcl.type.splice-2.sentence-2)
[3](#dcl.type.splice-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L2352)
For a [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]") of the formtypenameopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]"),
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") of
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]") shall designate a template T that is either a class template or an alias template[.](#dcl.type.splice-3.sentence-1)
The [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9Type splicing[dcl.type.splice]") designates
the specialization of T corresponding to
the template argument list of the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]")[.](#dcl.type.splice-3.sentence-2)