[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 struct P { };using cell = P; // 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(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(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); // 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)
**Specifier(s)** | **Type** | | --- | --- | | [🔗](#tab:dcl.type.simple-row-2)
[*type-name*](#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") | the type named | | [🔗](#tab:dcl.type.simple-row-3)
[*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)
[*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)
[*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)
[*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)
[*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)
[*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)
char | “char” | | [🔗](#tab:dcl.type.simple-row-10)
unsigned char | “unsigned char” | | [🔗](#tab:dcl.type.simple-row-11)
signed char | “signed char” | | [🔗](#tab:dcl.type.simple-row-12)
char8_t | “char8_t” | | [🔗](#tab:dcl.type.simple-row-13)
char16_t | “char16_t” | | [🔗](#tab:dcl.type.simple-row-14)
char32_t | “char32_t” | | [🔗](#tab:dcl.type.simple-row-15)
bool | “bool” | | [🔗](#tab:dcl.type.simple-row-16)
unsigned | “unsigned int” | | [🔗](#tab:dcl.type.simple-row-17)
unsigned int | “unsigned int” | | [🔗](#tab:dcl.type.simple-row-18)
signed | “int” | | [🔗](#tab:dcl.type.simple-row-19)
signed int | “int” | | [🔗](#tab:dcl.type.simple-row-20)
int | “int” | | [🔗](#tab:dcl.type.simple-row-21)
unsigned short int | “unsigned short int” | | [🔗](#tab:dcl.type.simple-row-22)
unsigned short | “unsigned short int” | | [🔗](#tab:dcl.type.simple-row-23)
unsigned long int | “unsigned long int” | | [🔗](#tab:dcl.type.simple-row-24)
unsigned long | “unsigned long int” | | [🔗](#tab:dcl.type.simple-row-25)
unsigned long long int | “unsigned long long int” | | [🔗](#tab:dcl.type.simple-row-26)
unsigned long long | “unsigned long long int” | | [🔗](#tab:dcl.type.simple-row-27)
signed long int | “long int” | | [🔗](#tab:dcl.type.simple-row-28)
signed long | “long int” | | [🔗](#tab:dcl.type.simple-row-29)
signed long long int | “long long int” | | [🔗](#tab:dcl.type.simple-row-30)
signed long long | “long long int” | | [🔗](#tab:dcl.type.simple-row-31)
long long int | “long long int” | | [🔗](#tab:dcl.type.simple-row-32)
long long | “long long int” | | [🔗](#tab:dcl.type.simple-row-33)
long int | “long int” | | [🔗](#tab:dcl.type.simple-row-34)
long | “long int” | | [🔗](#tab:dcl.type.simple-row-35)
signed short int | “short int” | | [🔗](#tab:dcl.type.simple-row-36)
signed short | “short int” | | [🔗](#tab:dcl.type.simple-row-37)
short int | “short int” | | [🔗](#tab:dcl.type.simple-row-38)
short | “short int” | | [🔗](#tab:dcl.type.simple-row-39)
wchar_t | “wchar_t” | | [🔗](#tab:dcl.type.simple-row-40)
float | “float” | | [🔗](#tab:dcl.type.simple-row-41)
double | “double” | | [🔗](#tab:dcl.type.simple-row-42)
long double | “long double” | | [🔗](#tab:dcl.type.simple-row-43)
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