[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.1 General [dcl.spec.general]")  
[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]")  
[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]")  
[*function-specifier*](#nt:function-specifier "9.2.3 Function specifiers [dcl.fct.spec]")  
friend  
typedef  
constexpr  
consteval  
constinit  
inline

[decl-specifier-seq:](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]")  
[*decl-specifier*](#nt:decl-specifier "9.2.1 General [dcl.spec.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt  
[*decl-specifier*](#nt:decl-specifier "9.2.1 General [dcl.spec.general]") [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]")

The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") appertains to the type determined by the preceding[*decl-specifier*](#nt:decl-specifier "9.2.1 General [dcl.spec.general]")*s* ([[dcl.meaning]](dcl.meaning "9.3.4 Meaning of declarators"))[.](#general-1.sentence-2)

The [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute 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.1 General [dcl.spec.general]")*s*friend, typedef, or inline shall appear in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [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.1 General [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.3 Simple type specifiers [dcl.type.simple]") is encountered while parsing a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]"),
it is interpreted as part of the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") if and only if there is no
previous [*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]") other than a [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]") in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [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.1 General [dcl.type.general]") (other thanconst or volatile) has to be present to indicate that
the [*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") Pc is the name being (re)declared,
rather than being part of the [*decl-specifier*](#nt:decl-specifier "9.2.1 General [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.3 Simple 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.2 Storage class specifiers [dcl.stc]")  
static  
thread_local  
extern  
mutable

At most one [*storage-class-specifier*](#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]") shall appear in a given[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [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.2 Storage class specifiers [dcl.stc]") appears in a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]"), there can be notypedef specifier in the same [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") and
the [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1 General [dcl.decl.general]") or [*member-declarator-list*](class.mem.general#nt:member-declarator-list "11.4.1 General [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.2 Anonymous unions")))[.](#dcl.stc-1.sentence-4)

The[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]") applies to the name declared by each[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1 General [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.4 Explicit specialization") and [[temp.explicit]](temp.explicit "13.9.3 Explicit 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.2 Storage 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.4 Automatic 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.3 Thread 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.7 Structured 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.2 Storage class specifiers [dcl.stc]") static is implied if no other[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]") appears in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [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.7 Structured binding declarations")), or
to the declaration of an anonymous union ([[class.union.anon]](class.union.anon "11.5.2 Anonymous 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.2 Static 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.3 Thread storage duration"))[.](#dcl.stc-4.sentence-3)

A static specifier can be
used in declarations of class members; [[class.static]](class.static "11.4.9 Static 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.7 Program 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.7 Program 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.3 Explicit instantiation [temp.explicit]")*s* and[*linkage-specification*](dcl.link#nt:linkage-specification "9.12 Linkage specifications [dcl.link]")*s*, but it is not a[*storage-class-specifier*](#nt:storage-class-specifier "9.2.2 Storage 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.4 Class 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.5 CV-qualifiers"), [[dcl.type.cv]](#dcl.type.cv "9.2.9.2 The 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.3 Function 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.3 Function specifiers [dcl.fct.spec]") and
at most one virtual keyword shall appear in
a [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]")[.](#dcl.fct.spec-1.sentence-2)

[function-specifier:](#nt:function-specifier "9.2.3 Function specifiers [dcl.fct.spec]")  
virtual  
[*explicit-specifier*](#nt:explicit-specifier "9.2.3 Function specifiers [dcl.fct.spec]")

[explicit-specifier:](#nt:explicit-specifier "9.2.3 Function specifiers [dcl.fct.spec]")  
explicit ( [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant 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.3 Virtual 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.3 Function 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.2 Conversion by constructor") and [[class.conv.fct]](class.conv.fct "11.4.8.3 Conversion 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.3 Function specifiers [dcl.fct.spec]"),
the [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]"), if supplied, shall be a
contextually converted constant expression of type bool ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#dcl.fct.spec-4.sentence-1)

The [*explicit-specifier*](#nt:explicit-specifier "9.2.3 Function specifiers [dcl.fct.spec]") explicit without a [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") is equivalent to
the [*explicit-specifier*](#nt:explicit-specifier "9.2.3 Function 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.3 Function 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.1 General [dcl.spec.general]") typedef declare [*type aliases*](#def:alias,type "9.2.4 The 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.1 General [dcl.spec.general]") with any other kind of
specifier except a [*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]"), and it shall not be used in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") of a[*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) nor in the[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") of a[*function-definition*](dcl.fct.def.general#nt:function-definition "9.6.1 General [dcl.fct.def.general]") ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions"))[.](#dcl.typedef-1.sentence-2)

If a typedef specifier appears in a declaration without a [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]"),
the program is ill-formed[.](#dcl.typedef-1.sentence-3)

[typedef-name:](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]")  
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")  
[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")

A name declared with the typedef specifier becomes a[*typedef-name*](#nt:typedef-name "9.2.4 The 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.11 Identifiers [lex.name]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))
or [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") ([[temp.pre]](temp.pre "13.1 Preamble"))[.](#dcl.typedef-1.sentence-5)

A [*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") does not introduce a new type the way a class
declaration ([[class.name]](class.name "11.3 Class names")) or enum declaration ([[dcl.enum]](dcl.enum "9.8.1 Enumeration 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.1 Preamble [dcl.pre]")[.](#dcl.typedef-2.sentence-1)

The [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") following theusing keyword is not looked up;
it becomes the [*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") of a type alias
and the optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") following the[*identifier*](lex.name#nt:identifier "5.11 Identifiers [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.2 Point of declaration")) â *end example*]

The [*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1 General [dcl.type.general]") of the [*defining-type-id*](dcl.name#nt:defining-type-id "9.3.2 Type names [dcl.name]") shall not define
a class or enumeration if the [*alias-declaration*](dcl.pre#nt:alias-declaration "9.1 Preamble [dcl.pre]") is the [*declaration*](dcl.pre#nt:declaration "9.1 Preamble [dcl.pre]") of a [*template-declaration*](temp.pre#nt:template-declaration "13.1 Preamble [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.3 Names of template specializations [temp.names]") is only a [*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") if its [*template-name*](temp.names#nt:template-name "13.3 Names 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.3 Names of template specializations [temp.names]") that names a class template specialization
is a [*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") ([[class.name]](class.name "11.3 Class names"))[.](#dcl.typedef-3.sentence-2)

If a [*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") is used to identify the subject of an[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]") ([[dcl.type.elab]](#dcl.type.elab "9.2.9.5 Elaborated type specifiers")), a [class
definition](class "11 Classes [class]"), a [constructor
declaration](class.ctor "11.4.5 Constructors [class.ctor]"), or a [destructor
declaration](class.dtor "11.4.7 Destructors [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.4 The 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.4 The typedef specifier [dcl.typedef]") ([[basic.link]](basic.link "6.7 Program 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.1 General [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.1 General [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.4 Friends")[.](#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.8 The 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.7 Constant 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.6 The 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.7 Constant 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.6 The constexpr and consteval specifiers [dcl.constexpr]") if
it is not a coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine 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.7 Constant 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.6 Copy/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.7 Constant 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.7 Structured 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.3 Dynamic 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.2 Static 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.6 Functions"), [[class.mfct]](class.mfct "11.4.2 Member functions"), [[class.friend]](class.friend "11.8.4 Friends"))
with an inline specifier declares an[*inline function*](#def:function,inline "9.2.8 The 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.7 Program 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.8 The 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.3 One-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.6 The 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.2 Member functions"), [[class.friend]](class.friend "11.8.4 Friends"))[.](#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.1 General [dcl.type.general]")  
[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]")  
[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]")  
[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1 General [temp.res.general]")  
[*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]")

[type-specifier-seq:](#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]")  
[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt  
[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]")

[defining-type-specifier:](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]")  
[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")  
[*class-specifier*](class.pre#nt:class-specifier "11.1 Preamble [class.pre]")  
[*enum-specifier*](dcl.enum#nt:enum-specifier "9.8.1 Enumeration declarations [dcl.enum]")

[defining-type-specifier-seq:](#nt:defining-type-specifier-seq "9.2.9.1 General [dcl.type.general]")  
[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt  
[*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]") [*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1 General [dcl.type.general]")

The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]") or a [*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1 General [dcl.type.general]") appertains
to the type denoted by the preceding [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* or [*defining-type-specifier*](#nt:defining-type-specifier "9.2.9.1 General [dcl.type.general]")*s* ([[dcl.meaning]](dcl.meaning "9.3.4 Meaning of declarators"))[.](#dcl.type.general-1.sentence-2)

The[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute 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.1 General [dcl.type.general]") is allowed in the complete[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") of a [*declaration*](dcl.pre#nt:declaration "9.1 Preamble [dcl.pre]") or in a[*defining-type-specifier-seq*](#nt:defining-type-specifier-seq "9.2.9.1 General [dcl.type.general]"),
and at most one[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") is allowed in a[*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1 General [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.1 General [dcl.type.general]") that is not a[*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]") shall appear in a complete[*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]") or a complete[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [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.1 Enumeration declarations [dcl.enum]")*s*,[*class-specifier*](class.pre#nt:class-specifier "11.1 Preamble [class.pre]")*s*,
and[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1 General [temp.res.general]")*s* are discussed
in[[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations"),[[class]](class "11 Classes"),
and[[temp.res]](temp.res "13.8 Name resolution"), respectively[.](#dcl.type.general-4.sentence-1)

The remaining[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* are discussed in the rest of [[dcl.type]](#dcl.type "9.2.9 Type 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.1 General [dcl.spec.general]") that
lacks a [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") or that has a[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") that only specifies [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [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.1 General [dcl.decl.general]")*s*, const andvolatile[.](#dcl.type.cv-1.sentence-1)

Each [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]") shall appear at most once in
a [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]")[.](#dcl.type.cv-1.sentence-2)

If a [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]") appears in a[*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]"), the [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1 General [dcl.decl.general]") or [*member-declarator-list*](class.mem.general#nt:member-declarator-list "11.4.1 General [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.5 CV-qualifiers") and [[dcl.fct]](dcl.fct "9.3.4.6 Functions") 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.2 Storage class specifiers"))
and its usability in constant expressions ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#dcl.type.cv-2.sentence-1)

As
described in [[dcl.init]](dcl.init "9.5 Initializers"), 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.11 Const 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.19 Assignment and compound assignment operators"), [[expr.post.incr]](expr.post.incr "7.6.1.6 Increment and decrement"), [[expr.pre.incr]](expr.pre.incr "7.6.2.3 Increment and decrement")) a
const object ([[basic.type.qualifier]](basic.type.qualifier "6.9.5 CV-qualifiers")) during its
lifetime ([[basic.life]](basic.life "6.8.4 Lifetime")) 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.1 Sequential 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.3 Simple type specifiers [dcl.type.simple]")  
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*type-name*](#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]")  
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") template [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")  
[*computed-type-specifier*](#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]")  
[*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]")  
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*template-name*](temp.names#nt:template-name "13.3 Names 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.3 Simple type specifiers [dcl.type.simple]")  
[*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]")  
[*enum-name*](dcl.enum#nt:enum-name "9.8.1 Enumeration declarations [dcl.enum]")  
[*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]")

[computed-type-specifier:](#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]")  
[*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]")  
[*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4 Pack indexing specifier [dcl.type.pack.index]")  
[*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9 Type 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.3 Simple type specifiers [dcl.type.simple]") are those of its[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]"),[*type-name*](#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]"),[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]"),[*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]"), and/or[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") (if it is a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]"))[.](#dcl.type.simple-2.sentence-1)

The component name of a [*type-name*](#nt:type-name "9.2.9.3 Simple 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.1 General [dcl.spec.auto.general]") is a placeholder for
a type to be deduced ([[dcl.spec.auto]](#auto "9.2.9.7 Placeholder type specifiers"))[.](#dcl.type.simple-3.sentence-1)

A [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") is a placeholder for
a deduced class type ([[dcl.type.class.deduct]](#dcl.type.class.deduct "9.2.9.8 Deduced 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.3 Qualified names [expr.prim.id.qual]")opt [*template-name*](temp.names#nt:template-name "13.3 Names 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.6 Splice specifiers [basic.splice]") and
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice 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.3 Qualified names [expr.prim.id.qual]") or [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]"),
if any, shall be non-dependent and
the [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") or [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") shall designate a deducible template[.](#dcl.type.simple-3.sentence-3)

A [*deducible template*](#def:template,deducible "9.2.9.3 Simple 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.2 Type names [dcl.name]") is of the form

typenameopt [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")

where the [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") (if any) is non-dependent and
the [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") of the [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names 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.3 Names of template specializations [temp.names]") in contexts where class template argument deduction would be performed ([[temp.local]](temp.local "13.8.2 Locally declared names"))[.](#dcl.type.simple-3.sentence-6)

â *end note*]

The other[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3 Simple 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.2 Fundamental 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.3 Simple 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.3 Simple 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.3 Simple 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.3 Names of template specializations [temp.names]") | the type as defined in [[temp.names]](temp.names "13.3 Names of template specializations") |
| [ð](#tab:dcl.type.simple-row-4)<br>[*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]") | the type as defined in [[dcl.type.decltype]](#dcl.type.decltype "9.2.9.6 Decltype specifiers") |
| [ð](#tab:dcl.type.simple-row-5)<br>[*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4 Pack indexing specifier [dcl.type.pack.index]") | the type as defined in [[dcl.type.pack.index]](#dcl.type.pack.index "9.2.9.4 Pack indexing specifier") |
| [ð](#tab:dcl.type.simple-row-6)<br>[*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]") | the type as defined in [[dcl.spec.auto]](#auto "9.2.9.7 Placeholder type specifiers") |
| [ð](#tab:dcl.type.simple-row-7)<br>[*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") | the type as defined in [[dcl.type.class.deduct]](#dcl.type.class.deduct "9.2.9.8 Deduced class template specialization types") |
| [ð](#tab:dcl.type.simple-row-8)<br>[*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9 Type splicing [dcl.type.splice]") | the type as defined in [[dcl.type.splice]](#dcl.type.splice "9.2.9.9 Type 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.3 Simple type specifiers [dcl.type.simple]")*s* are allowed, they can be
freely intermixed with other [*decl-specifier*](#nt:decl-specifier "9.2.1 General [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.4 Pack indexing specifier [dcl.type.pack.index]")  
[*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") ... [ [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant 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.4 The typedef specifier [dcl.typedef]") P in a [*pack-index-specifier*](#nt:pack-index-specifier "9.2.9.4 Pack 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.7 Constant expressions [expr.const]") shall be
a converted constant expression ([[expr.const]](expr.const "7.7 Constant 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.4 Pack indexing specifier [dcl.type.pack.index]") is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic 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.4 Pack 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.5 Elaborated type specifiers [dcl.type.elab]")  
[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")  
[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")  
[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")  
enum [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [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.5 Elaborated type specifiers [dcl.type.elab]") are
its [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") (if any) and
those of its [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") and[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names 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.5 Elaborated 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.4 Explicit specialization")),
a partial specialization ([[temp.spec.partial]](temp.spec.partial "13.7.6 Partial specialization")),
an explicit
instantiation ([[temp.explicit]](temp.explicit "13.9.3 Explicit instantiation")), or it has one of the following
forms:

[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ;  
[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") ;

In the first case,
the [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]") declares
the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") as a [*class-name*](class.pre#nt:class-name "11.1 Preamble [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.4 Explicit specialization [temp.expl.spec]") ([[temp.expl.spec]](temp.expl.spec "13.9.4 Explicit specialization")) or
in a [*template-declaration*](temp.pre#nt:template-declaration "13.1 Preamble [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.1 Attribute 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.5 Elaborated type specifiers [dcl.type.elab]") E shall not have
an [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")[.](#dcl.type.elab-3.sentence-1)

If E contains an [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") but no [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") and
(unqualified) lookup for the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") finds nothing,E shall not be introduced by the enum keyword and
declares the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") as a [*class-name*](class.pre#nt:class-name "11.1 Preamble [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.1 General [class.mem.general]") that is an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]") shall have one of the following forms:

[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")  
[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")  
[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")

Any unqualified lookup for the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [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.4 Using 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.6 Elaborated type specifiers") describes how name lookup proceeds
in an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]")[.](#dcl.type.elab-5.sentence-1)

An [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]") can be used to refer to
a previously declared [*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") or [*enum-name*](dcl.enum#nt:enum-name "9.8.1 Enumeration 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.11 Identifiers [lex.name]") or [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") in an [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]") resolves to a [*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") or[*enum-name*](dcl.enum#nt:enum-name "9.8.1 Enumeration declarations [dcl.enum]"), the [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]") introduces it into the declaration the same way a[*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") introduces
its [*type-name*](#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") ([[dcl.type.simple]](#dcl.type.simple "9.2.9.3 Simple type specifiers"))[.](#dcl.type.elab-6.sentence-1)

If the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") or [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") resolves to a[*typedef-name*](#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") ([[dcl.typedef]](#dcl.typedef "9.2.4 The typedef specifier"), [[temp.names]](temp.names "13.3 Names of template specializations")),
the [*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated 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.2 Template 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.4 Friends"))[.](#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.1 Preamble [class.pre]") or enum keyword
present in an[*elaborated-type-specifier*](#nt:elaborated-type-specifier "9.2.9.5 Elaborated 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.5 Elaborated 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.5 Elaborated type specifiers [dcl.type.elab]") that declares a[*class-name*](class.pre#nt:class-name "11.1 Preamble [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.5 Elaborated type specifiers [dcl.type.elab]"), the enum keyword
shall be
used to refer to an enumeration ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations")), the union[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") shall be used to refer to a union ([[class.union]](class.union "11.5 Unions")),
and either the class or struct[*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") shall be used to refer to a non-union class ([[class.pre]](class.pre "11.1 Preamble"))[.](#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.6 Decltype specifiers [dcl.type.decltype]")  
decltype ( [*expression*](expr.comma#nt:expression "7.6.20 Comma 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.1 General [expr.prim.id.general]") naming a structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured 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.1 General [expr.prim.id.general]") naming a constant template parameter ([[temp.param]](temp.param "13.2 Template parameters")),decltype(E) is the type of the template parameter
after performing any necessary
type deduction ([[dcl.spec.auto]](#auto "9.2.9.7 Placeholder type specifiers"), [[dcl.type.class.deduct]](#dcl.type.class.deduct "9.2.9.8 Deduced 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.1 General [expr.prim.id.general]") or
an unparenthesized
class
member access ([[expr.ref]](expr.ref "7.6.1.5 Class 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.9 Expression 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.6 Splice 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.3 Context 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.7 Placeholder 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.6 Decltype specifiers [dcl.type.decltype]") is a prvalue
and is not a (possibly parenthesized) immediate invocation ([[expr.const]](expr.const "7.7 Constant expressions")),
the temporary materialization conversion is not applied ([[conv.rval]](conv.rval "7.3.5 Temporary 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.6 Decltype specifiers [dcl.type.decltype]") is analogous to a use of a [*typedef-name*](#nt:typedef-name "9.2.4 The 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.3 Template argument deduction")) because A<int>​::​~A() is implicitly used in its// [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype 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.6 Decltype 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.1 General [dcl.spec.auto.general]")  
[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")opt auto  
[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [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.6 Functions [dcl.fct]") of a

- [(2.1)](#auto.general-2.1)

function declaration ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),

- [(2.2)](#auto.general-2.2)

[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6 Lambda expressions")), or

- [(2.3)](#auto.general-2.3)

[*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template parameters"))

can be declared using
a [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]") of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [dcl.spec.general]")*s* in
the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") or
as one of the [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") that specifies the type that replaces such
a [*decl-specifier*](#nt:decl-specifier "9.2.1 General [dcl.spec.general]") (see below);
the placeholder type
is a [*generic parameter type placeholder*](#def:generic_parameter_type_placeholder "9.2.9.7.1 General [dcl.spec.auto.general]") of the
function declaration,[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"), or[*template-parameter*](temp.param#nt:template-parameter "13.2 Template 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.6 Functions")) or
the lambda is a generic lambda ([[expr.prim.lambda]](expr.prim.lambda "7.5.6 Lambda 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.1 General [dcl.spec.general]") for a function declarator
that includes a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#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.1 General [dcl.spec.general]") or [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1 General [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.2 The 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.5 Initializers")) of a variable[.](#auto.general-5.sentence-2)

The placeholder type shall appear as one of the[*decl-specifier*](#nt:decl-specifier "9.2.1 General [dcl.spec.general]")*s* in the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") or as one of the[*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") that specifies the type that replaces such a [*decl-specifier*](#nt:decl-specifier "9.2.1 General [dcl.spec.general]");
the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") shall be followed by one or more[*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]")*s*,
each of which shall
be followed by a non-empty[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [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.2 Storage 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.1 General [dcl.type.general]") can also be used to introduce
a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured 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.1 General [dcl.type.general]") of
the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8 New [expr.new]") or
in the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") of a[*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") ([[expr.new]](expr.new "7.6.2.8 New"))[.](#auto.general-6.sentence-1)

In such a [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]"),
the placeholder type shall appear
as one of the [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in
the [*type-specifier-seq*](#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]") or
as one of the [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]")*s* in
a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") that specifies the type that replaces such a [*type-specifier*](#nt:type-specifier "9.2.9.1 General [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.1 General [dcl.type.general]") can also be used
as the [*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") in an explicit type conversion (functional notation) ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit 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.7 Placeholder 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.1 General [dcl.decl.general]") contains more than one[*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1 General [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.2 Placeholder 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.5 Private 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.7 Program 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.3 One-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.2 Referring 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.3 Template 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.3 Virtual 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.4 Coroutine 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.3 Explicit 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.2 Placeholder 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.1 General [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.1 General [dcl.init.general]") ([[dcl.init.list]](dcl.init.list "9.5.5 List-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.20 Comma operator [expr.comma]") X that is not an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.20 Comma operator")) is not
an [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.2 Template parameters [temp.param]")opt decltype(auto) orcv [*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [dcl.init.general]") of the form = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]"),E is the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [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.1 General [dcl.init.general]"),
it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.1 General [expr.post.general]"),
the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") shall be
a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.4 Explicit 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.1 General [dcl.init.general]"),
it shall consist of a single brace-enclosed [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.1 General [expr.post.general]"),
the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") shall be
a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") and E is the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment 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.1 General [dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General"))
the [*placeholder-type-specifier*](#nt:placeholder-type-specifier "9.2.9.7.1 General [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.2 Template 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.2 Deducing 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.1 General [dcl.spec.auto.general]") is of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.6 Decltype 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.1 General [dcl.spec.auto.general]") with a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]"),
the immediately-declared constraint ([[temp.param]](temp.param "13.2 Template parameters"))
of the [*type-constraint*](temp.param#nt:type-constraint "13.2 Template 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.1 General [dcl.spec.general]") in the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") of an initializing declaration ([[dcl.init]](dcl.init "9.5 Initializers")) 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.9 Class template argument deduction"))[.](#dcl.type.class.deduct-1.sentence-2)

If the [*decl-specifier-seq*](#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") is followed by an [*init-declarator-list*](dcl.decl.general#nt:init-declarator-list "9.3.1 General [dcl.decl.general]") or [*member-declarator-list*](class.mem.general#nt:member-declarator-list "11.4.1 General [class.mem.general]") containing more than one [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [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.1 General [dcl.type.general]") in the [*new-type-id*](expr.new#nt:new-type-id "7.6.2.8 New [expr.new]") or [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") of a [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") ([[expr.new]](expr.new "7.6.2.8 New")),
as the [*simple-type-specifier*](#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") in an [explicit type conversion (functional notation)](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation) [expr.type.conv]"),
or
as the [*type-specifier*](#nt:type-specifier "9.2.9.1 General [dcl.type.general]") in the [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") of a [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template 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.9 Type splicing [dcl.type.splice]")  
typenameopt [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")  
typenameopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice 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.6 Splice specifiers [basic.splice]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") immediately followed by ​::​ is never interpreted as part of a [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9 Type splicing [dcl.type.splice]")[.](#dcl.type.splice-1.sentence-1)

A [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") not preceded by typename is only interpreted as a [*splice-type-specifier*](#nt:splice-type-specifier "9.2.9.9 Type splicing [dcl.type.splice]") within a type-only context ([[temp.res.general]](temp.res.general "13.8.1 General"))[.](#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.9 Type splicing [dcl.type.splice]") of the formtypenameopt [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]"),
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice 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.9 Type splicing [dcl.type.splice]") designates
the same entity as the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice 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.9 Type splicing [dcl.type.splice]") of the formtypenameopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]"),
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") of
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice 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.9 Type 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.6 Splice specifiers [basic.splice]")[.](#dcl.type.splice-3.sentence-2)
