1815 lines
118 KiB
Markdown
1815 lines
118 KiB
Markdown
[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)
|