Working Draft, Standard for Programming Language C++ (N4713, 2017 year) - page 6

 

  Главная      Manuals     Working Draft, Standard for Programming Language C++ (N4713, 2017 year)

 

Search            copyright infringement  

 

 

 

 

 

 

 

 

 

 

 

Content      ..     4      5      6      7     ..

 

 

 

Working Draft, Standard for Programming Language C++ (N4713, 2017 year) - page 6

 

 

When thread_local is applied to a variable of block scope the storage-class-specifier static is implied if no
other storage-class-specifier appears in the decl-specifier-seq.
4
The static specifier can be applied only to names of variables and functions and to anonymous unions (12.3.1).
There can be no static function declarations within a block, nor any static function parameters. A static
specifier used in the declaration of a variable declares the variable to have static storage duration (6.6.4.1),
unless accompanied by the thread_local specifier, which declares the variable to have thread storage
duration (6.6.4.2). A static specifier can be used in declarations of class members; 12.2.3 describes its effect.
For the linkage of a name declared with a static specifier, see 6.5.
5
The extern specifier can be applied only to the names of variables and functions. The extern specifier
cannot be used in the declaration of class members or function parameters. For the linkage of a name declared
with an extern specifier, see 6.5. [ Note: The extern keyword can also be used in explicit-instantiations and
linkage-specifications, but it is not a storage-class-specifier in such contexts.
— end note ]
6
The linkages implied by successive declarations for a given entity shall agree. That is, within a given scope,
each declaration declaring the same variable name or the same overloading of a function name shall imply
the same linkage. Each function in a given set of overloaded functions can have a different linkage, however.
[ Example:
static char* f();
// f() has internal linkage
char* f()
// f() still has internal linkage
{ /* ... */ }
char* g();
// g() has external linkage
static char* g()
// error: inconsistent linkage
{ /* ... */ }
void h();
inline void h();
// external linkage
inline void l();
void l();
// external linkage
inline void m();
extern void m();
// external linkage
static void n();
inline void n();
// internal linkage
static int a;
// a has internal linkage
int a;
// error: two definitions
static int b;
// b has internal linkage
extern int b;
// b still has internal linkage
int c;
// c has external linkage
static int c;
// error: inconsistent linkage
extern int d;
// d has external linkage
static int d;
// error: inconsistent linkage
— end example ]
7
The name of a declared but undefined class can be used in an extern declaration. Such a declaration can
only be used in ways that do not require a complete class type. [ Example:
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
}
§ 10.1.1
142
— end example ]
8
The mutable specifier shall appear only in the declaration of a non-static data member (12.2) whose type is
neither const-qualified nor a reference type. [ Example:
class X {
mutable const int* p;
// OK
mutable int* const q;
// ill-formed
};
— end example ]
9
The mutable specifier on a class data member nullifies a const specifier applied to the containing class object
and permits modification of the mutable class member even though the rest of the object is const (10.1.7.1).
10.1.2
Function specifiers
[dcl.fct.spec]
1
Function-specifier s can be used only in function declarations.
function-specifier:
virtual
explicit
2
The virtual specifier shall be used only in the initial declaration of a non-static class member function;
see 13.3.
3
The explicit specifier shall be used only in the declaration of a constructor or conversion function within
its class definition; see 15.3.1 and 15.3.2.
10.1.3
The typedef specifier
[dcl.typedef]
1
Declarations containing the decl-specifier typedef declare identifiers that can be used later for naming
fundamental (6.7.1) or compound (6.7.2) types. The typedef specifier shall not be combined in a decl-
specifier-seq with any other kind of specifier except a defining-type-specifier, and it shall not be used in the
decl-specifier-seq of a parameter-declaration (11.3.5) nor in the decl-specifier-seq of a function-definition (11.4).
If a typedef specifier appears in a declaration without a declarator, the program is ill-formed.
typedef-name:
identifier
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a
typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in the
way described in Clause 11. A typedef-name is thus a synonym for another type. A typedef-name does not
introduce a new type the way a class declaration (12.1) or enum declaration does. [ Example: After
typedef int MILES, *KLICKSP;
the constructions
MILES distance;
extern KLICKSP metricp;
are all correct declarations; the type of distance is int and that of metricp is “pointer to int”.
— end
example ]
2
A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword
becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that
typedef-name. Such a typedef-name has the same semantics as if it were introduced by the typedef specifier.
In particular, it does not define a new type. [ Example:
using handler_t = void (*)(int);
extern handler_t ignore;
extern void (*ignore)(int);
// redeclare ignore
using cell = pair<void*, cell*>;
// ill-formed
— end example ] The defining-type-specifier-seq of the defining-type-id shall not define a class or enumeration
if the alias-declaration is the declaration of a template-declaration.
3
In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that
scope to refer to the type to which it already refers. [ Example:
typedef struct s { /* ... */ } s;
typedef int I;
§ 10.1.3
143
typedef int I;
typedef I I;
— end example ]
4
In a given class scope, a typedef specifier can be used to redefine any class-name declared in that scope that
is not also a typedef-name to refer to the type to which it already refers. [ Example:
struct S {
typedef struct A { } A;
// OK
typedef struct B B;
// OK
typedef A A;
// error
};
— end example ]
5
If a typedef specifier is used to redefine in a given scope an entity that can be referenced using an elaborated-
type-specifier, the entity can continue to be referenced by an elaborated-type-specifier or as an enumeration or
class name in an enumeration or class definition respectively. [ Example:
struct S;
typedef struct S S;
int main() {
struct S* p;
// OK
}
struct S { };
// OK
— end example ]
6
In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that
scope to refer to a different type. [ Example:
class complex { /* ... */ };
typedef int complex;
// error: redefinition
— end example ]
7
Similarly, in a given scope, a class or enumeration shall not be declared with the same name as a typedef-name
that is declared in that scope and refers to a type other than the class or enumeration itself. [ Example:
typedef int complex;
class complex { /* ... */ };
// error: redefinition
— end example ]
8
[ Note: A typedef-name that names a class type, or a cv-qualified version thereof, is also a class-name (12.1). If
a typedef-name is used to identify the subject of an elaborated-type-specifier (10.1.7.3), a class definition (Clause
12), a constructor declaration (15.1), or a destructor declaration (15.4), the program is ill-formed.
— end
note ]
[ Example:
struct S {
S();
~S();
};
typedef struct S T;
S a = T();
// OK
struct T * p;
// error
— end example ]
9
If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the
declaration to be that class type (or enum type) is used to denote the class type (or enum type) for linkage
purposes only (6.5). [Note: A typedef declaration involving a lambda-expression does not itself define the
associated closure type, and so the closure type is not given a name for linkage purposes.
— end note ]
[ Example:
typedef struct { } *ps, S;
// S is the class name for linkage purposes
typedef decltype([]{}) C;
// the closure type has no name for linkage purposes
— end example ]
§ 10.1.3
144
10.1.4
The friend specifier
[dcl.friend]
1
The friend specifier is used to specify access to class members; see 14.3.
10.1.5
The constexpr specifier
[dcl.constexpr]
1
The constexpr specifier shall be applied only to the definition of a variable or variable template or the
declaration of a function or function template. A function or static data member declared with the constexpr
specifier is implicitly an inline function or variable (10.1.6). If any declaration of a function or function
template has a constexpr specifier, then all its declarations shall contain the constexpr specifier. [ Note:
An explicit specialization can differ from the template declaration with respect to the constexpr specifier.
— end note ] [ Note: Function parameters cannot be declared constexpr. — end note ]
[ Example:
constexpr void square(int &x);
// OK: declaration
constexpr int bufsz = 1024;
// OK: definition
constexpr struct pixel {
// error: pixel is a type
int 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 (8.6) so constexpr not satisfied
constexpr void square(int &x) { // OK: definition
x *= x;
}
constexpr pixel large(4);
// OK: square defined
int next(constexpr int x) {
// error: not for parameters
return x + 1;
}
extern constexpr int memsz;
// error: not a definition
— end example ]
2
A constexpr specifier used in the declaration of a function that is not a constructor declares that function
to be a constexpr function. Similarly, a constexpr specifier used in a constructor declaration declares that
constructor to be a constexpr constructor.
3
The definition of a constexpr function shall satisfy the following requirements:
(3.1)
it shall not be virtual (13.3);
(3.2)
its return type shall be a literal type;
(3.3)
each of its parameter types shall be a literal type;
(3.4)
its function-body shall be = delete, = default, or a compound-statement that does not contain
(3.4.1)
an asm-definition,
(3.4.2)
a goto statement,
(3.4.3)
an identifier label (9.1),
(3.4.4)
a try-block, or
(3.4.5)
a definition of a variable of non-literal type or of static or thread storage duration or for which no
initialization is performed.
[ Example:
constexpr int square(int x)
{ return x * x; }
// OK
constexpr long long_max()
{ return 2147483647; }
// OK
constexpr int abs(int x) {
if (x < 0)
x = -x;
§ 10.1.5
145
return x;
// OK
}
constexpr int first(int n) {
static int value = n;
// error: variable has static storage duration
return value;
}
constexpr int uninit() {
int a;
// error: variable is uninitialized
return a;
}
constexpr int prev(int x)
{ return --x; }
// OK
constexpr int g(int x, int n) { // OK
int r = 1;
while (--n > 0) r *= x;
return r;
}
— end example ]
4
The definition of a constexpr constructor shall satisfy the following requirements:
(4.1)
the class shall not have any virtual base classes;
(4.2)
each of the parameter types shall be a literal type;
(4.3)
its function-body shall not be a function-try-block.
In addition, either its function-body shall be = delete, or it shall satisfy the following requirements:
(4.4)
either its function-body shall be = default, or the compound-statement of its function-body shall satisfy
the requirements for a function-body of a constexpr function;
(4.5)
every non-variant non-static data member and base class subobject shall be initialized (15.6.2);
(4.6)
if the class is a union having variant members (12.3), exactly one of them shall be initialized;
(4.7)
if the class is a union-like class, but is not a union, for each of its anonymous union members having
variant members, exactly one of them shall be initialized;
(4.8)
for a non-delegating constructor, every constructor selected to initialize non-static data members and
base class subobjects shall be a constexpr constructor;
(4.9)
for a delegating constructor, the target constructor shall be a constexpr constructor.
[ Example:
struct Length {
constexpr explicit Length(int i = 0) : val(i) { }
private:
int val;
};
— end example ]
5
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument
values exist such that an invocation of the function or constructor could be an evaluated subexpression of
a core constant expression (8.6), or, for a constructor, a constant initializer for some object (6.8.3.2), the
program is ill-formed, no diagnostic required. [ Example:
constexpr int f(bool b)
{ return b ? throw 0 : 0; }
// OK
constexpr int f() { return f(true); }
// ill-formed, no diagnostic required
struct B {
constexpr B(int x) : i(0) { }
// x is unused
int i;
};
int global;
§ 10.1.5
146
struct D : B {
constexpr D() : B(global) { }
// ill-formed, no diagnostic required
// lvalue-to-rvalue conversion on non-constant global
};
— end example ]
6
If the instantiated template specialization of a constexpr function template or member function of a class
template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that
specialization is still a constexpr function or constexpr constructor, even though a call to such a function
cannot appear in a constant expression. If no specialization of the template would satisfy the requirements
for a constexpr function or constexpr constructor when considered as a non-template function or constructor,
the template is ill-formed, no diagnostic required.
7
A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in
all respects except that
(7.1)
a call to a constexpr function can appear in a constant expression (8.6) and
(7.2)
copy elision is mandatory in a constant expression (15.8).
8
The constexpr specifier has no effect on the type of a constexpr function or a constexpr constructor.
[ Example:
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 ]
9
A constexpr specifier used in an object declaration declares the object as const. Such an object shall
have literal type and shall be initialized. In any constexpr variable declaration, the full-expression of the
initialization shall be a constant expression (8.6). [ Example:
struct pixel {
int x, y;
};
constexpr pixel ur = { 1294, 1024 };
// OK
constexpr pixel origin;
// error: initializer missing
— end example ]
10.1.6
The inline specifier
[dcl.inline]
1
The inline specifier can be applied only to the declaration or definition of a variable or function.
2
A function declaration (11.3.5, 12.2.1, 14.3) with an inline specifier declares an inline function. 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. 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.
3
A variable declaration with an inline specifier declares an inline variable.
4
A function defined within a class definition is an inline function.
5
The inline specifier shall not appear on a block scope declaration.96 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.
6
An inline function or variable shall be defined in every translation unit in which it is odr-used and shall
have exactly the same definition in every case (6.2). [ Note: A call to the inline function or a use of the
inline variable may be encountered before its definition appears in the translation unit.
— end note ] If the
definition of a function or variable appears in a translation unit before its first declaration as inline, the
program is ill-formed. If a function or variable with external linkage is declared inline in one translation
unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required. An
inline function or variable with external linkage shall have the same address in all translation units. [ Note:
96) The inline keyword has no effect on the linkage of a function.
§ 10.1.6
147
A static local variable in an inline function with external linkage always refers to the same object. A type
defined within the body of an inline function with external linkage is the same type in every translation unit.
— end note ]
10.1.7
Type specifiers
[dcl.type]
1
The type-specifiers are
type-specifier:
simple-type-specifier
elaborated-type-specifier
typename-specifier
cv-qualifier
type-specifier-seq:
type-specifier attribute-specifier-seqopt
type-specifier type-specifier-seq
defining-type-specifier:
type-specifier
class-specifier
enum-specifier
defining-type-specifier-seq:
defining-type-specifier attribute-specifier-seqopt
defining-type-specifier defining-type-specifier-seq
The optional attribute-specifier-seq in a type-specifier-seq or a defining-type-specifier-seq appertains to the
type denoted by the preceding type-specifier s or defining-type-specifier s (11.3). The attribute-specifier-seq
affects the type only for the declaration it appears in, not other declarations involving the same type.
2
As a general rule, at most one defining-type-specifier is allowed in the complete decl-specifier-seq of a
declaration or in a defining-type-specifier-seq, and at most one type-specifier is allowed in a type-specifier-seq.
The only exceptions to this rule are the following:
(2.1)
const can be combined with any type specifier except itself.
(2.2)
volatile can be combined with any type specifier except itself.
(2.3)
signed or unsigned can be combined with char, long, short, or int.
(2.4)
short or long can be combined with int.
(2.5)
long can be combined with double.
(2.6)
long can be combined with long.
3
Except in a declaration of a constructor, destructor, or conversion function, at least one defining-type-specifier
that is not a cv-qualifier shall appear in a complete type-specifier-seq or a complete decl-specifier-seq.97
4
[Note: enum-specifiers, class-specifiers, and typename-specifiers are discussed in 10.2, Clause 12, and 17.7,
respectively. The remaining type-specifier s are discussed in the rest of this subclause.
— end note ]
10.1.7.1
The cv-qualifiers
[dcl.type.cv]
1
There are two cv-qualifiers, const and volatile. Each cv-qualifier shall appear at most once in a cv-
qualifier-seq. If a cv-qualifier appears in a decl-specifier-seq, the init-declarator-list or member-declarator-list
of the declaration shall not be empty. [Note: 6.7.3 and 11.3.5 describe how cv-qualifiers affect object and
function types.
— end note ] Redundant cv-qualifications are ignored. [ Note: For example, these could be
introduced by typedefs. — end note ]
2
[ Note: Declaring a variable const can affect its linkage (10.1.1) and its usability in constant expressions (8.6).
As described in 11.6, the definition of an object or subobject of const-qualified type must specify an initializer
or be subject to default-initialization.
— end note ]
3
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. [ Note: Cv-qualifiers
are supported by the type system so that they cannot be subverted without casting (8.5.1.11).
— end note ]
97) 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.
§ 10.1.7.1
148
4
Except that any class member declared mutable (10.1.1) can be modified, any attempt to modify a const
object during its lifetime (6.6.3) results in undefined behavior. [ Example:
const int ci = 3;
// cv-qualified (initialized as required)
ci = 4;
// ill-formed: attempt to modify const
int i = 2;
// not cv-qualified
const int* cip;
// pointer to const int
cip = &i;
// OK: cv-qualified access path to unqualified
*cip = 4;
// ill-formed: attempt to modify through ptr to const
int* ip;
ip = const_cast<int*>(cip);
// cast needed to convert const int* to int*
*ip = 4;
// defined: *ip points to i, a non-const object
const int* ciq = new const int (3);
// initialized as required
int* iq = const_cast<int*>(ciq);
// cast required
*iq = 4;
// undefined: 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++;
// ill-formed: 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: modifies a const subobject
— end example ]
5
The semantics of an access through a volatile glvalue are implementation-defined. 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.
6
[ Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because
the value of the object might be changed by means undetectable by an implementation. Furthermore, for
some implementations, volatile might indicate that special hardware instructions are required to access the
object. See 6.8.1 for detailed semantics. In general, the semantics of volatile are intended to be the same
in C++ as they are in C. — end note ]
10.1.7.2
Simple type specifiers
[dcl.type.simple]
1
The simple type specifiers are
§ 10.1.7.2
149
simple-type-specifier:
nested-name-specifieropt type-name
nested-name-specifier template simple-template-id
nested-name-specifieropt template-name
char
char16_t
char32_t
wchar_t
bool
short
int
long
signed
unsigned
float
double
void
auto
decltype-specifier
type-name:
class-name
enum-name
typedef-name
simple-template-id
decltype-specifier:
decltype ( expression )
decltype ( auto )
2
The simple-type-specifier auto is a placeholder for a type to be deduced (10.1.7.4). A type-specifier of the form
typenameopt nested-name-specifieropt template-name is a placeholder for a deduced class type (10.1.7.5). The
template-name shall name a class template that is not an injected-class-name. The other simple-type-specifier s
specify either a previously-declared type, a type determined from an expression, or one of the fundamental
types (6.7.1). Table 11 summarizes the valid combinations of simple-type-specifier s and the types they specify.
3
When multiple simple-type-specifier s are allowed, they can be freely intermixed with other decl-specifier s in
any order. [ Note: It is implementation-defined whether objects of char type are represented as signed or
unsigned quantities. The signed specifier forces char objects to be signed; it is redundant in other contexts.
— end note ]
4
For an expression e, the type denoted by decltype(e) is defined as follows:
(4.1)
if e is an unparenthesized id-expression naming a structured binding (11.5), decltype(e) is the
referenced type as given in the specification of the structured binding declaration;
(4.2)
otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access (8.5.1.5),
decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of
overloaded functions, the program is ill-formed;
(4.3)
otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
(4.4)
otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
(4.5)
otherwise, decltype(e) is the type of e.
The operand of the decltype specifier is an unevaluated operand (8.2).
[ Example:
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 int
decltype(a->x) x3;
// type is double
decltype((a->x)) x4 = x3;
// type is const double&
§ 10.1.7.2
150
Table 11 — simple-type-specifier s and the types they specify
Specifier(s)
Type
type-name
the type named
simple-template-id
the type as defined in 17.2
template-name
placeholder for a type to be deduced
char
“char”
unsigned char
“unsigned char”
signed char
“signed char”
char16_t
“char16_t”
char32_t
“char32_t”
bool
“bool”
unsigned
“unsigned int”
unsigned int
“unsigned int”
signed
“int”
signed int
“int”
int
“int”
unsigned short int
“unsigned short int”
unsigned short
“unsigned short int”
unsigned long int
“unsigned long int”
unsigned long
“unsigned long int”
unsigned long long int
“unsigned long long int”
unsigned long long
“unsigned long long int”
signed long int
“long int”
signed long
“long int”
signed long long int
“long long int”
signed long long
“long long int”
long long int
“long long int”
long long
“long long int”
long int
“long int”
long
“long int”
signed short int
“short int”
signed short
“short int”
short int
“short int”
short
“short int”
wchar_t
“wchar_t”
float
“float”
double
“double”
long double
“long double”
void
“void”
auto
placeholder for a type to be deduced
decltype(auto)
placeholder for a type to be deduced
decltype(expression)
the type as defined below
— end example ] [ Note: The rules for determining types involving decltype(auto) are specified in 10.1.7.4.
— end note ]
5
If the operand of a decltype-specifier is a prvalue, the temporary materialization conversion is not applied (7.4)
and no result object is provided for the prvalue. The type of the prvalue may be incomplete. [Note: As a
result, storage is not allocated for the prvalue and it is not destroyed. Thus, a class type is not instantiated
as a result of being the type of a function call in this context. In this context, the common purpose of
writing the expression is merely to refer to its type. In that sense, a decltype-specifier is analogous to a use
of a typedef-name, so the usual reasons for requiring a complete type do not apply. 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.
— end note ] [ Note: Unlike the preceding rule, parentheses have no special
meaning in this context.
— end note ] [ Example:
template<class T> struct A { ~A() = delete; };
§ 10.1.7.2
151
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 (17.9.2) because A<int>::~A() is implicitly used in its
// decltype-specifier)
}
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
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 ]
10.1.7.3
Elaborated type specifiers
[dcl.type.elab]
elaborated-type-specifier:
class-key attribute-specifier-seqopt nested-name-specifieropt identifier
class-key simple-template-id
class-key nested-name-specifier templateopt simple-template-id
enum nested-name-specifieropt identifier
1
An attribute-specifier-seq shall not appear in an elaborated-type-specifier unless the latter is the sole constituent
of a declaration. If an elaborated-type-specifier is the sole constituent of a declaration, the declaration is
ill-formed unless it is an explicit specialization (17.8.3), an explicit instantiation (17.8.2) or it has one of the
following forms:
class-key attribute-specifier-seqopt identifier ;
friend class-key ::opt identifier ;
friend class-key ::opt simple-template-id ;
friend class-key nested-name-specifier identifier ;
friend class-key nested-name-specifier templateopt simple-template-id ;
In the first case, the attribute-specifier-seq, if any, appertains to the class being declared; the attributes in the
attribute-specifier-seq are thereafter considered attributes of the class whenever it is named.
2
6.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier
resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the
same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef-name or
the simple-template-id resolves to an alias template specialization, the elaborated-type-specifier is ill-formed.
[ Note: This implies that, within a class template with a template type-parameter T, the declaration
friend class T;
is ill-formed. However, the similar declaration friend T; is allowed (14.3).
— end note ]
3
The class-key or enum keyword present in the elaborated-type-specifier shall agree in kind with the declaration
to which the name in the elaborated-type-specifier refers. This rule also applies to the form of elaborated-type-
specifier that declares a class-name or friend class since it can be construed as referring to the definition of the
class. Thus, in any elaborated-type-specifier, the enum keyword shall be used to refer to an enumeration (10.2),
the union class-key shall be used to refer to a union (Clause 12), and either the class or struct class-key
shall be used to refer to a class (Clause 12) declared using the class or struct class-key. [ Example:
enum class E { a, b };
enum E x = E::a;
// OK
§ 10.1.7.3
152
— end example ]
10.1.7.4
The auto specifier
[dcl.spec.auto]
1
The auto and decltype(auto) type-specifier s are used to designate a placeholder type that will be replaced
later by deduction from an initializer. The auto type-specifier is also used to introduce a function type having
a trailing-return-type or to signify that a lambda is a generic lambda (8.4.5). The auto type-specifier is also
used to introduce a structured binding declaration (11.5).
2
The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq,
conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function
declarator includes a trailing-return-type (11.3.5), that trailing-return-type specifies the declared return type
of the function. Otherwise, the function declarator shall declare a function. If the declared return type of the
function contains a placeholder type, the return type of the function is deduced from non-discarded return
statements, if any, in the body of the function (9.4.1).
3
The type of a variable declared using auto or decltype(auto) is deduced from its initializer. This use is
allowed in an initializing declaration (11.6) of a variable. auto or decltype(auto) shall appear as one of the
decl-specifier s in the decl-specifier-seq and the decl-specifier-seq shall be followed by one or more declarator s,
each of which shall be followed by a non-empty initializer. In an initializer of the form
( expression-list
)
the expression-list shall be a single assignment-expression. [ Example:
auto x = 5;
// OK: x has type int
const auto *v = &x, u = 6;
// OK: v has type const int*, u has type const int
static auto y = 0.0;
// OK: y has type double
auto int r;
// error: auto is not a storage-class-specifier
auto f() -> int;
// OK: f returns int
auto g() { return 0.0; }
// OK: g returns double
auto h();
// OK: h’s return type will be deduced when it is defined
— end example ]
4
A placeholder type can also be used in the type-specifier-seq in the new-type-id or type-id of a new-
expression (8.5.2.4) and as a decl-specifier of the parameter-declaration’s decl-specifier-seq in a template-
parameter (17.1).
5
A program that uses auto or decltype(auto) in a context not explicitly allowed in this subclause is ill-formed.
6
If the init-declarator-list contains more than one init-declarator, they shall all form declarations of variables.
The type of each declared variable is determined by placeholder type deduction (10.1.7.4.1), and if the type
that replaces the placeholder type is not the same in each deduction, the program is ill-formed.
[ Example:
auto x = 5, *y = &x;
// OK: auto is int
auto a = 5, b = { 1, 2 };
// error: different types for auto
— end example ]
7
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. If the type deduced is not the same
in each deduction, the program is ill-formed.
8
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 a return statement with no operand at the closing brace of the
function body. [ Example:
auto f() { }
// OK, return type is void
auto* g() { }
// error, cannot deduce auto* from void()
— end example ]
9
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression,
the program is ill-formed. 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 other return
statements. [ Example:
auto n = n;
// error, n’s type is unknown
auto f();
§ 10.1.7.4
153
void g() { &f; }
// error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i;
// sum’s return type is int
else
return sum(i-1)+i;
// OK, sum’s return type has been deduced
}
— end example ]
10
Return type deduction for a function template 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.
[Note: Therefore, any use of a specialization of the function template will cause an implicit
instantiation. 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 (17.9.2).
— end note ] [ Example:
template <class T> auto f(T t) { return t; }
// return type deduced at instantiation time
typedef decltype(f(1)) fint_t;
// instantiates f<int> to deduce return type
template<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 ]
11
Redeclarations or specializations of a function or function template with a declared return type that uses a
placeholder type shall also use that placeholder, not a deduced type. [ Example:
auto f();
auto f() { return 42; }
// return type is int
auto f();
// OK
int f();
// error, cannot be overloaded with auto f()
decltype(auto) f();
// error, auto and decltype(auto) don’t match
template <typename T> auto g(T t) { return t; } // #1
template auto g(int);
// OK, return type is int
template char g(char);
// error, no matching template
template<> auto g(double);
// OK, forward declaration with unknown return type
template <class T> T g(T t) { return t; }
// OK, not functionally equivalent to #1
template char g(char);
// OK, now there is a matching template
template auto g(float);
// still matches #1
void h() { return g(42); }
// error, ambiguous
template <typename T> struct A {
friend T frf(T);
};
auto frf(int i) { return i; }
// not a friend of A<int>
— end example ]
12
A function declared with a return type that uses a placeholder type shall not be virtual (13.3).
13
An explicit instantiation declaration (17.8.2) 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. [ Example:
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 ]
10.1.7.4.1
Placeholder type deduction
[dcl.type.auto.deduct]
1
Placeholder type deduction is the process by which a type containing a placeholder type is replaced by a
deduced type.
2
A type T containing a placeholder type, and a corresponding initializer e, are determined as follows:
§ 10.1.7.4.1
154
(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 and e is the operand of the return statement. If the
return statement has no operand, then e is void();
(2.2)
for a variable declared with a type that contains a placeholder type, T is the declared type of the
variable and e is the initializer. If the initialization is direct-list-initialization, the initializer shall be a
braced-init-list containing only a single assignment-expression and e is the assignment-expression;
(2.3)
for a non-type template parameter declared with a type that contains a placeholder type, T is the
declared type of the non-type template parameter and e is the corresponding template argument.
In the case of a return statement with no operand or with an operand of type void, T shall be either
decltype(auto) or cv auto.
3
If the deduction is for a return statement and e is a braced-init-list (11.6.4), the program is ill-formed.
4
If the placeholder is the auto type-specifier, the deduced type T replacing T is determined using the rules for
template argument deduction. Obtain P from T by replacing the occurrences of auto with either a new invented
type template parameter U or, if the initialization is copy-list-initialization, with std::initializer_list<U>.
Deduce a value for U using the rules of template argument deduction from a function call (17.9.2.1), where
P is a function template parameter type and the corresponding argument is e. If the deduction fails, the
declaration is ill-formed. Otherwise, T is obtained by substituting the deduced U into P. [ Example:
auto x1 = { 1, 2 };
// decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 };
// error: cannot deduce element type
auto x3{ 1, 2 };
// error: not a single element
auto x4 = { 3 };
// decltype(x4) is std::initializer_list<int>
auto x5{ 3 };
// decltype(x5) is int
— end example ]
[ Example:
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 ]
5
If the placeholder is the decltype(auto) type-specifier, T shall be the placeholder alone. The type deduced for
T is determined as described in 10.1.7.2, as though e had been the operand of the decltype. [ Example:
int i;
int&& f();
auto
x2a(i);
// decltype(x2a) is int
decltype(auto) x2d(i);
// decltype(x2d) is int
auto
x3a = i;
// decltype(x3a) is int
decltype(auto) x3d = i;
// decltype(x3d) is int
auto
x4a = (i);
// decltype(x4a) is int
decltype(auto) x4d = (i);
// decltype(x4d) is int&
auto
x5a = f();
// decltype(x5a) is int
decltype(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 expression
auto
*x7a = &i;
// decltype(x7a) is int*
decltype(auto)*x7d = &i;
// error, declared type is not plain decltype(auto)
— end example ]
10.1.7.5
Deduced class template specialization types
[dcl.type.class.deduct]
1
If a placeholder for a deduced class type appears as a decl-specifier in the decl-specifier-seq of an initializing
declaration (11.6) of a variable, the placeholder is replaced by the return type of the function selected
by overload resolution for class template deduction (16.3.1.8). If the decl-specifier-seq is followed by an
init-declarator-list or member-declarator-list containing more than one declarator, the type that replaces the
placeholder shall be the same in each deduction.
§ 10.1.7.5
155
2
A placeholder for a deduced class type can also be used in the type-specifier-seq in the new-type-id or
type-id of a new-expression (8.5.2.4), or as the simple-type-specifier in an explicit type conversion (functional
notation) (8.5.1.3). A placeholder for a deduced class type shall not appear in any other context.
3
[ Example:
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 T
auto d = container(v.begin(), v.end()); // OK, deduces double for T
container e{5, 6};
// error, int is not an iterator
— end example ]
10.2
Enumeration declarations
[dcl.enum]
1
An enumeration is a distinct type (6.7.2) with named constants. Its name becomes an enum-name within its
scope.
enum-name:
identifier
enum-specifier:
enum-head { enumerator-listopt }
enum-head { enumerator-list , }
enum-head:
enum-key attribute-specifier-seqopt enum-head-nameopt enum-baseopt
enum-head-name:
nested-name-specifieropt identifier
opaque-enum-declaration:
enum-key attribute-specifier-seqopt nested-name-specifieropt identifier enum-baseopt ;
enum-key:
enum
enum class
enum struct
enum-base:
: type-specifier-seq
enumerator-list:
enumerator-definition
enumerator-list , enumerator-definition
enumerator-definition:
enumerator
enumerator = constant-expression
enumerator:
identifier attribute-specifier-seqopt
The optional attribute-specifier-seq in the enum-head and the opaque-enum-declaration appertains to the enu-
meration; the attributes in that attribute-specifier-seq are thereafter considered attributes of the enumeration
whenever it is named. A : following “enum nested-name-specifieropt identifier” within the decl-specifier-seq
of a member-declaration is parsed as part of an enum-base.
[Note: This resolves a potential ambiguity
between the declaration of an enumeration with an enum-base and the declaration of an unnamed bit-field of
enumeration type. [ Example:
struct S {
enum E : int {};
enum E : int {};
// error: redeclaration of enumeration
};
§ 10.2
156
— end example ] — end note ] If an opaque-enum-declaration contains a nested-name-specifier, the declaration
shall be an explicit specialization (17.8.3).
2
The enumeration type declared with an enum-key of only enum is an unscoped enumeration, and its enumerator s
are unscoped enumerators. The enum-keys enum class and enum struct are semantically equivalent; an
enumeration type declared with one of these is a scoped enumeration, and its enumerator s are scoped
enumerators. The optional identifier shall not be omitted in the declaration of a scoped enumeration.
The type-specifier-seq of an enum-base shall name an integral type; any cv-qualification is ignored. An
opaque-enum-declaration declaring an unscoped enumeration shall not omit the enum-base. The identifiers in
an enumerator-list are declared as constants, and can appear wherever constants are required. An enumerator-
definition with = gives the associated enumerator the value indicated by the constant-expression. If the first
enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition
without an initializer gives the enumerator the value obtained by increasing the value of the previous
enumerator by one. [ Example:
enum { a, b, c=0 };
enum { d, e, f=e+2 };
defines a, c, and d to be zero, b and e to be 1, and f to be 3.
— end example ] The optional attribute-
specifier-seq in an enumerator appertains to that enumerator.
3
An opaque-enum-declaration is either a redeclaration of an enumeration in the current scope or a declaration
of a new enumeration. [ Note: An enumeration declared by an opaque-enum-declaration has fixed underlying
type and is a complete type. The list of enumerators can be provided in a later redeclaration with an
enum-specifier.
— end note ] A scoped enumeration shall not be later redeclared as unscoped or with
a different underlying type. An unscoped enumeration shall not be later redeclared as scoped and each
redeclaration shall include an enum-base specifying the same underlying type as in the original declaration.
4
If the enum-key is followed by a nested-name-specifier, the enum-specifier shall refer to an enumeration that
was previously declared directly in the class or namespace to which the nested-name-specifier refers (i.e.,
neither inherited nor introduced by a using-declaration), and the enum-specifier shall appear in a namespace
enclosing the previous declaration.
5
Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying
type. The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the
underlying type is int if it is not explicitly specified. In both of these cases, the underlying type is said to be
fixed. Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration. If
the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type
and the constant-expression in the enumerator-definition shall be a converted constant expression of the
underlying type (8.6). If the underlying type is not fixed, the type of each enumerator prior to the closing
brace is determined as follows:
(5.1)
If an initializer is specified for an enumerator, the constant-expression shall be an integral constant
expression (8.6). If the expression has unscoped enumeration type, the enumerator has the underlying
type of that enumeration type, otherwise it has the same type as the expression.
(5.2)
If no initializer is specified for the first enumerator, its type is an unspecified signed integral type.
(5.3)
Otherwise the type of the enumerator is the same as that of the preceding enumerator unless the
incremented value is not representable in that type, in which case the type is an unspecified integral
type sufficient to contain the incremented value. If no such type exists, the program is ill-formed.
6
An enumeration whose underlying type is fixed is an incomplete type from its point of declaration (6.3.2)
to immediately after its enum-base (if any), at which point it becomes a complete type. An enumeration
whose underlying type is not fixed is an incomplete type from its point of declaration to immediately after
the closing } of its enum-specifier, at which point it becomes a complete type.
7
For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can
represent all the enumerator values defined in the enumeration. If no integral type can represent all the
enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used
as the underlying type except that the underlying type shall not be larger than int unless the value of an
enumerator cannot fit in an int or unsigned int. If the enumerator-list is empty, the underlying type is as
if the enumeration had a single enumerator with value 0.
8
For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the
underlying type. Otherwise, for an enumeration where emin is the smallest enumerator and emax is the largest,
§ 10.2
157
the values of the enumeration are the values in the range bmin to bmax, defined as follows: Let K be 1 for
a two’s complement representation and 0 for a ones’ complement or sign-magnitude representation. bmax
is the smallest value greater than or equal to max(|emin| − K,|emax|) and equal to 2M 1, where M is a
non-negative integer. bmin is zero if emin is non-negative and(bmax + K) otherwise. The size of the smallest
bit-field large enough to hold all the values of the enumeration type is max(M, 1) if bmin is zero and M + 1
otherwise. It is possible to define an enumeration that has values not defined by any of its enumerators. If
the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator
with value 0.98
9
Two enumeration types are layout-compatible enumerations if they have the same underlying type.
10
The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by
integral promotion (7.6). [ Example:
enum color { red, yellow, green=20, blue };
color col = red;
color* cp = &col;
if (*cp == blue)
// ...
makes color a type describing various colors, and then declares col as an object of that type, and cp as a
pointer to an object of that type. The possible values of an object of type color are red, yellow, green,
blue; these values can be converted to the integral values 0, 1, 20, and 21. Since enumerations are distinct
types, objects of type color can be assigned only values of type color.
color c = 1;
// error: type mismatch, no conversion from int to color
int i = yellow;
// OK: yellow converted to integral value 1, integral promotion
Note that this implicit enum to int conversion is not provided for a scoped enumeration:
enum class Col { red, yellow, green };
int x = Col::red;
// error: no Col to int conversion
Col y = Col::red;
if (y) { }
// error: no Col to bool conversion
— end example ]
11
Each enum-name and each unscoped enumerator is declared in the scope that immediately contains the
enum-specifier. Each scoped enumerator is declared in the scope of the enumeration. These names obey the
scope rules defined for all names in 6.3 and 6.4. [ Example:
enum direction { left=’l’, right=’r’ };
void g()
{
direction d;
// OK
d = left;
// OK
d = direction::right;
// OK
}
enum class altitude { high=’h’, low=’l’ };
void h()
{
altitude a;
// OK
a = high;
// error: high not in scope
a = altitude::low;
// OK
}
— end example ] An enumerator declared in class scope can be referred to using the class member access
operators (::, . (dot) and -> (arrow)), see 8.5.1.5. [ Example:
struct X {
enum direction { left=’l’, right=’r’ };
int f(int i) { return i==left ? 0 : i==right ? 1 : 2; }
};
void g(X* p) {
direction d;
// error: direction not in scope
98) This set of values is used to define promotion and conversion semantics for the enumeration type. It does not preclude an
expression of enumeration type from having a value that falls outside this range.
§ 10.2
158
int i;
i = p->f(left);
// error: left not in scope
i = p->f(X::right);
// OK
i = p->f(p->left);
// OK
// ...
}
— end example ]
12
If an enum-head contains a nested-name-specifier, the enum-specifier shall refer to an enumeration that was
previously declared directly in the class or namespace to which the nested-name-specifier refers, or in an
element of the inline namespace set (10.3.1) of that namespace (i.e., not merely inherited or introduced by a
using-declaration), and the enum-specifier shall appear in a namespace enclosing the previous declaration. In
such cases, the nested-name-specifier of the enum-head of the definition shall not begin with a decltype-specifier.
10.3
Namespaces
[basic.namespace]
1
A namespace is an optionally-named declarative region. The name of a namespace can be used to access
entities declared in that namespace; that is, the members of the namespace. Unlike other declarative regions,
the definition of a namespace can be split over several parts of one or more translation units.
2
The outermost declarative region of a translation unit is a namespace; see 6.3.6.
10.3.1
Namespace definition
[namespace.def]
namespace-name:
identifier
namespace-alias
namespace-definition:
named-namespace-definition
unnamed-namespace-definition
nested-namespace-definition
named-namespace-definition:
inlineopt namespace attribute-specifier-seqopt identifier { namespace-body }
unnamed-namespace-definition:
inlineopt namespace attribute-specifier-seqopt { namespace-body }
nested-namespace-definition:
namespace enclosing-namespace-specifier :: identifier { namespace-body }
enclosing-namespace-specifier:
identifier
enclosing-namespace-specifier :: identifier
namespace-body:
declaration-seqopt
1
Every namespace-definition shall appear in the global scope or in a namespace scope (6.3.6).
2
In a named-namespace-definition, the identifier is the name of the namespace. If the identifier, when looked
up (6.4.1), refers to a namespace-name (but not a namespace-alias) that was introduced in the namespace in
which the named-namespace-definition appears or that was introduced in a member of the inline namespace
set of that namespace, the namespace-definition extends the previously-declared namespace. Otherwise, the
identifier is introduced as a namespace-name into the declarative region in which the named-namespace-
definition appears.
3
Because a namespace-definition contains declarations in its namespace-body and a namespace-definition is
itself a declaration, it follows that namespace-definitions can be nested. [ Example:
namespace Outer {
int i;
namespace Inner {
void f() { i++; }
// Outer::i
int i;
void g() { i++; }
// Inner::i
}
}
§ 10.3.1
159
— end example ]
4
The enclosing namespaces of a declaration are those namespaces in which the declaration lexically appears,
except for a redeclaration of a namespace member outside its original namespace (e.g., a definition as
specified in 10.3.1.2). Such a redeclaration has the same enclosing namespaces as the original declaration.
[ Example:
namespace Q {
namespace V {
void f();
// enclosing namespaces are the global namespace, Q, and Q::V
class C { void m(); };
}
void V::f() {
// enclosing namespaces are the global namespace, Q, and Q::V
extern void h();
// ... so this declares Q::V::h
}
void V::C::m() {
// enclosing namespaces are the global namespace, Q, and Q::V
}
}
— end example ]
5
If the optional initial inline keyword appears in a namespace-definition for a particular namespace, that
namespace is declared to be an inline namespace. The inline keyword may be used on a namespace-definition
that extends a namespace only if it was previously used on the namespace-definition that initially declared
the namespace-name for that namespace.
6
The optional attribute-specifier-seq in a named-namespace-definition appertains to the namespace being
defined or extended.
7
Members of an inline namespace can be used in most respects as though they were members of the enclosing
namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of
associated namespaces used in argument-dependent lookup (6.4.2) whenever one of them is, and a using-
directive (10.3.4) that names the inline namespace is implicitly inserted into the enclosing namespace as for
an unnamed namespace (10.3.1.1). Furthermore, each member of the inline namespace can subsequently
be partially specialized (17.6.5), explicitly instantiated (17.8.2), or explicitly specialized (17.8.3) as though
it were a member of the enclosing namespace. Finally, looking up a name in the enclosing namespace via
explicit qualification (6.4.3.2) will include members of the inline namespace brought in by the using-directive
even if there are declarations of that name in the enclosing namespace.
8
These properties are transitive: if a namespace N contains an inline namespace M, which in turn contains an
inline namespace O, then the members of O can be used as though they were members of M or N. The inline
namespace set of N is the transitive closure of all inline namespaces in N. The enclosing namespace set of O is
the set of namespaces consisting of the innermost non-inline namespace enclosing an inline namespace O,
together with any intervening inline namespaces.
9
A nested-namespace-definition with an enclosing-namespace-specifier E, identifier I and namespace-body B is
equivalent to
namespace E { namespace I { B } }
[ Example:
namespace A::B::C {
int i;
}
The above has the same effect as:
namespace A {
namespace B {
namespace C {
int i;
}
}
}
— end example ]
§ 10.3.1
160
10.3.1.1
Unnamed namespaces
[namespace.unnamed]
1
An unnamed-namespace-definition behaves as if it were replaced by
inlineopt namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
where inline appears if and only if it appears in the unnamed-namespace-definition and all occurrences of
unique in a translation unit are replaced by the same identifier, and this identifier differs from all other
identifiers in the translation unit. The optional attribute-specifier-seq in the unnamed-namespace-definition
appertains to unique. [ Example:
namespace { int i; }
// unique::i
void f() { i++; }
// unique::i++
namespace A {
namespace {
int i;
// A::unique::i
int j;
// A::unique::j
}
void g() { i++; }
// A::unique::i++
}
using namespace A;
void h() {
i++;
// error: unique::i or A::unique::i
A::i++;
// A::unique::i
j++;
// A::unique::j
}
— end example ]
10.3.1.2
Namespace member definitions
[namespace.memdef]
1
A declaration in a namespace N (excluding declarations in nested scopes) whose declarator-id is an unqualified-
id (11.3), whose class-head-name (Clause 12) or enum-head-name (10.2) is an identifier, or whose elaborated-
type-specifier is of the form class-key attribute-specifier-seqopt identifier (10.1.7.3), or that is an opaque-enum-
declaration, declares (or redeclares) its unqualified-id or identifier as a member of N. [ Note: An explicit
instantiation (17.8.2) or explicit specialization (17.8.3) of a template does not introduce a name and thus
may be declared using an unqualified-id in a member of the enclosing namespace set, if the primary template
is declared in an inline namespace.
— end note ] [ Example:
namespace X {
void f() { /* ... */ }
// OK: introduces X::f()
namespace M {
void g();
// OK: introduces X::M::g()
}
using M::g;
void g();
// error: conflicts with X::M::g()
}
— end example ]
2
Members of a named namespace can also be defined outside that namespace by explicit qualification (6.4.3.2)
of the name being defined, provided that the entity being defined was already declared in the namespace and
the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.
[ Example:
namespace Q {
namespace V {
void f();
}
void V::f() { /* ... */ }
// OK
void V::g() { /* ... */ }
// error: g() is not yet a member of V
namespace V {
void g();
§ 10.3.1.2
161
}
}
namespace R {
void Q::V::g() { /* ... */ }
// error: R doesn’t enclose Q
}
— end example ]
3
If a friend declaration in a non-local class first declares a class, function, class template or function template99
the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make
the name visible to unqualified lookup (6.4.1) or qualified lookup (6.4.3). [ Note: The name of the friend will
be visible in its namespace if a matching declaration is provided at namespace scope (either before or after
the class definition granting friendship).
— end note ] If a friend function or function template is called, its
name may be found by the name lookup that considers functions from namespaces and classes associated
with the types of the function arguments (6.4.2). If the name in a friend declaration is neither qualified
nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine
whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing
namespace. [Note: The other forms of friend declarations cannot declare a new member of the innermost
enclosing namespace and thus follow the usual lookup rules.
— end note ]
[ Example:
// Assume f and g have not yet been declared.
void h(int);
template <class T> void f2(T);
namespace A {
class X {
friend void f(X);
// A::f(X) is a friend
class Y {
friend void g();
// A::g is a friend
friend void h(int);
// A::h is a friend
// ::h not considered
friend void f2<>(int);
// ::f2<>(int) is a friend
};
};
// A::f, A::g and A::h are not visible here
X x;
void g() { f(x); }
// definition of A::g
void f(X) { /* ... */ }
// definition of A::f
void h(int) { /* ... */ }
// definition of A::h
// A::f, A::g and A::h are visible here and known to be friends
}
using A::x;
void h() {
A::f(x);
A::X::f(x);
// error: f is not a member of
A::X
A::X::Y::g();
// error: g is not a member of
A::X::Y
}
— end example ]
10.3.2
Namespace alias
[namespace.alias]
1
A namespace-alias-definition declares an alternate name for a namespace according to the following grammar:
namespace-alias:
identifier
namespace-alias-definition:
namespace identifier = qualified-namespace-specifier ;
qualified-namespace-specifier:
nested-name-specifieropt namespace-name
99) this implies that the name of the class or function is unqualified.
§ 10.3.2
162
2
The identifier in a namespace-alias-definition is a synonym for the name of the namespace denoted by the
qualified-namespace-specifier and becomes a namespace-alias. [ Note: When looking up a namespace-name in
a namespace-alias-definition, only namespace names are considered, see 6.4.6.
— end note ]
3
In a declarative region, a namespace-alias-definition can be used to redefine a namespace-alias declared in
that declarative region to refer only to the namespace to which it already refers. [Example: The following
declarations are well-formed:
namespace Company_with_very_long_name { /* ... */ }
namespace CWVLN = Company_with_very_long_name;
namespace CWVLN = Company_with_very_long_name;
// OK: duplicate
namespace CWVLN = CWVLN;
— end example ]
10.3.3
The using declaration
[namespace.udecl]
using-declaration:
using using-declarator-list ;
using-declarator-list:
using-declarator ...opt
using-declarator-list , using-declarator ...opt
using-declarator:
typenameopt nested-name-specifier unqualified-id
1
Each using-declarator in a using-declaration100 introduces a set of declarations into the declarative region in
which the using-declaration appears. The set of declarations introduced by the using-declarator is found by
performing qualified name lookup (6.4.3, 13.2) for the name in the using-declarator, excluding functions that
are hidden as described below. If the using-declarator does not name a constructor, the unqualified-id is
declared in the declarative region in which the using-declaration appears as a synonym for each declaration
introduced by the using-declarator. [ Note: Only the specified name is so declared; specifying an enumeration
name in a using-declaration does not declare its enumerators in the using-declaration’s declarative region.
— end note ] If the using-declarator names a constructor, it declares that the class inherits the set of constructor
declarations introduced by the using-declarator from the nominated base class.
2
Every using-declaration is a declaration and a member-declaration and can therefore be used in a class
definition. [ Example:
struct B {
void f(char);
void g(char);
enum E { e };
union { int x; };
};
struct D : B {
using B::f;
void f(int) { f(’c’); }
// calls B::f(char)
void g(int) { g(’c’); }
// recursively calls D::g(int)
};
— end example ]
3
In a using-declaration used as a member-declaration, each using-declarator ’s nested-name-specifier shall name
a base class of the class being defined. If a using-declarator names a constructor, its nested-name-specifier
shall name a direct base class of the class being defined. [ Example:
template <typename... bases>
struct X : bases... {
using bases::g...;
};
X<B, D> x;
// OK: B::g and D::g introduced
100) A using-declaration with more than one using-declarator is equivalent to a corresponding sequence of using-declarations
with one using-declarator each.
§ 10.3.3
163
— end example ] [ Example:
class C {
int g();
};
class D2 : public B {
using B::f;
// OK: B is a base of D2
using B::e;
// OK: e is an enumerator of base B
using B::x;
// OK: x is a union member of base B
using C::g;
// error: C isn’t a base of D2
};
— end example ]
4
[Note: Since destructors do not have names, a using-declaration cannot refer to a destructor for a base
class. Since specializations of member templates for conversion functions are not found by name lookup,
they are not considered when a using-declaration specifies a conversion function (17.6.2).
— end note ] If
a constructor or assignment operator brought from a base class into a derived class has the signature of a
copy/move constructor or assignment operator for the derived class (15.8), the using-declaration does not by
itself suppress the implicit declaration of the derived class member; the member from the base class is hidden
or overridden by the implicitly-declared copy/move constructor or assignment operator of the derived class,
as described below.
5
A using-declaration shall not name a template-id. [ Example:
struct A {
template <class T> void f(T);
template <class T> struct X { };
};
struct B : A {
using A::f<double>;
// ill-formed
using A::X<int>;
// ill-formed
};
— end example ]
6
A using-declaration shall not name a namespace.
7
A using-declaration shall not name a scoped enumerator.
8
A using-declaration that names a class member shall be a member-declaration. [ Example:
struct X {
int i;
static int s;
};
void f() {
using X::i;
// error: X::i is a class member and this is not a member declaration.
using X::s;
// error: X::s is a class member and this is not a member declaration.
}
— end example ]
9
Members declared by a using-declaration can be referred to by explicit qualification just like other member
names (6.4.3.2). [ Example:
void f();
namespace A {
void g();
}
namespace X {
using ::f;
// global f
using A::g;
// A’s g
}
§ 10.3.3
164
void h()
{
X::f();
// calls ::f
X::g();
// calls A::g
}
— end example ]
10
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple
declarations are allowed. [ Example:
namespace A {
int i;
}
namespace A1 {
using A::i, A::i;
// OK: double declaration
}
struct B {
int i;
};
struct X : B {
using B::i, B::i;
// error: double member declaration
};
— end example ]
11
[Note: For a using-declaration whose nested-name-specifier names a namespace, members added to the
namespace after the using-declaration are not in the set of introduced declarations, so they are not considered
when a use of the name is made. Thus, additional overloads added after the using-declaration are ignored, but
default function arguments (11.3.6), default template arguments (17.1), and template specializations (17.6.5,
17.8.3) are considered.
— end note ] [ Example:
namespace A {
void f(int);
}
using A::f;
// f is a synonym for A::f; that is, for A::f(int).
namespace A {
void f(char);
}
void foo() {
f(’a’);
// calls f(int), even though f(char) exists.
}
void bar() {
using A::f;
// f is a synonym for A::f; that is, for A::f(int) and A::f(char).
f(’a’);
// calls f(char)
}
— end example ]
12
[ Note: Partial specializations of class templates are found by looking up the primary class template and then
considering all partial specializations of that template. If a using-declaration names a class template, partial
specializations introduced after the using-declaration are effectively visible because the primary template is
visible (17.6.5).
— end note ]
13
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same
declarative region (6.3) also apply to using-declarations. [ Example:
namespace A {
int x;
}
§ 10.3.3
165
namespace B {
int i;
struct g { };
struct x { };
void f(int);
void f(double);
void g(char);
// OK: hides struct g
}
void func() {
int i;
using B::i;
// error: i declared twice
void f(char);
using B::f;
// OK: each f is a function
f(3.5);
// calls B::f(double)
using B::g;
g(’a’);
// calls B::g(char)
struct g g1;
// g1 has class type B::g
using B::x;
using A::x;
// OK: hides struct B::x
x = 99;
// assigns to A::x
struct x x1;
// x1 has class type B::x
}
— end example ]
14
If a function declaration in namespace scope or block scope has the same name and the same parameter-
type-list (11.3.5) as a function introduced by a using-declaration, and the declarations do not declare the
same function, the program is ill-formed. If a function template declaration in namespace scope has the same
name, parameter-type-list, return type, and template parameter list as a function template introduced by a
using-declaration, the program is ill-formed. [Note: Two using-declarations may introduce functions with
the same name and the same parameter-type-list. If, for a call to an unqualified function name, function
overload resolution selects the functions introduced by such using-declarations, the function call is ill-formed.
[ Example:
namespace B {
void f(int);
void f(double);
}
namespace C {
void f(int);
void f(double);
void f(char);
}
void h() {
using B::f;
// B::f(int) and B::f(double)
using C::f;
// C::f(int), C::f(double), and C::f(char)
f(’h’);
// calls C::f(char)
f(1);
// error: ambiguous: B::f(int) or C::f(int)?
void f(int);
// error: f(int) conflicts with C::f(int) and B::f(int)
}
— end example ]
— end note ]
15
When a using-declarator brings declarations from a base class into a derived class, member functions and
member function templates in the derived class override and/or hide member functions and member function
templates with the same name, parameter-type-list (11.3.5), cv-qualification, and ref-qualifier (if any) in
a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of
declarations introduced by the using-declarator. [ Example:
struct B {
virtual void f(int);
virtual void f(char);
void g(int);
§ 10.3.3
166
void h(int);
};
struct D : B {
using B::f;
void f(int);
// OK: D::f(int) overrides B::f(int);
using B::g;
void g(char);
// OK
using B::h;
void h(int);
// OK: D::h(int) hides B::h(int)
};
void k(D* p)
{
p->f(1);
// calls D::f(int)
p->f(’a’);
// calls B::f(char)
p->g(1);
// calls B::g(int)
p->g(’a’);
// calls D::g(char)
}
struct B1 {
B1(int);
};
struct B2 {
B2(int);
};
struct D1 : B1,
B2
{
using B1::B1;
using B2::B2;
};
D1 d1(0);
// ill-formed: ambiguous
struct D2 : B1,
B2
{
using B1::B1;
using B2::B2;
D2(int);
// OK: D2::D2(int) hides B1::B1(int) and B2::B2(int)
};
D2 d2(0);
// calls D2::D2(int)
— end example ]
16
For the purpose of forming a set of candidates during overload resolution, the functions that are introduced
by a using-declaration into a derived class are treated as though they were members of the derived class. In
particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather
than to the base class. This has no effect on the type of the function, and in all other respects the function
remains a member of the base class. Likewise, constructors that are introduced by a using-declaration are
treated as though they were constructors of the derived class when looking up the constructors of the derived
class (6.4.3.1) or forming a set of overload candidates (16.3.1.3, 16.3.1.4, 16.3.1.7). If such a constructor is
selected to perform the initialization of an object of class type, all subobjects other than the base class from
which the constructor originated are implicitly initialized (15.6.3). [ Note: A member of a derived class is
sometimes preferred to a member of a base class if they would otherwise be ambiguous (16.3.3).
— end note ]
17
In a using-declarator that does not name a constructor, all members of the set of introduced declarations shall
be accessible. In a using-declarator that names a constructor, no access check is performed. In particular, if a
derived class uses a using-declarator to access a member of a base class, the member name shall be accessible.
If the name is that of an overloaded member function, then all functions named shall be accessible. The base
class members mentioned by a using-declarator shall be visible in the scope of at least one of the direct base
classes of the class where the using-declarator is specified.
§ 10.3.3
167
18
[ Note: Because a using-declarator designates a base class member (and not a member subobject or a member
function of a base class subobject), a using-declarator cannot be used to resolve inherited member ambiguities.
[ Example:
struct A { int x(); };
struct B : A { };
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int f(D* d) {
return d->x();
// error: overload resolution selects A::x, but A is an ambiguous base class
}
— end example ]
— end note ]
19
A synonym created by a using-declaration has the usual accessibility for a member-declaration. A using-
declarator that names a constructor does not create a synonym; instead, the additional constructors are
accessible if they would be accessible when used to construct an object of the corresponding base class, and
the accessibility of the using-declaration is ignored. [ Example:
class A {
private:
void f(char);
public:
void f(int);
protected:
void g();
};
class B : public A {
using A::f;
// error: A::f(char) is inaccessible
public:
using A::g;
// B::g is a public synonym for A::g
};
— end example ]
20
If a using-declarator uses the keyword typename and specifies a dependent name (17.7.2), the name introduced
by the using-declaration is treated as a typedef-name (10.1.3).
10.3.4
Using directive
[namespace.udir]
using-directive:
attribute-specifier-seqopt using namespace nested-name-specifieropt namespace-name ;
1
A using-directive shall not appear in class scope, but may appear in namespace scope or in block scope.
[Note: When looking up a namespace-name in a using-directive, only namespace names are considered,
see 6.4.6.
— end note ] The optional attribute-specifier-seq appertains to the using-directive.
2
A using-directive specifies that the names in the nominated namespace can be used in the scope in which the
using-directive appears after the using-directive. During unqualified name lookup (6.4.1), the names appear
as if they were declared in the nearest enclosing namespace which contains both the using-directive and the
nominated namespace. [Note: In this context, “contains” means “contains directly or indirectly”.
— end
note ]
3
A using-directive does not add any members to the declarative region in which it appears. [ Example:
namespace A {
int i;
namespace B {
namespace C {
int i;
}
§ 10.3.4
168
using namespace A::B::C;
void f1() {
i = 5;
// OK, C::i visible in B and hides A::i
}
}
namespace D {
using namespace B;
using namespace C;
void f2() {
i = 5;
// ambiguous, B::C::i or A::i?
}
}
void f3() {
i = 5;
// uses A::i
}
}
void f4() {
i = 5;
// ill-formed; neither i is visible
}
— end example ]
4
For unqualified lookup (6.4.1), the using-directive is transitive: if a scope contains a using-directive that
nominates a second namespace that itself contains using-directives, the effect is as if the using-directives
from the second namespace also appeared in the first. [ Note: For qualified lookup, see
6.4.3.2.
— end note ]
[ Example:
namespace M {
int i;
}
namespace N {
int i;
using namespace M;
}
void f() {
using namespace N;
i = 7;
// error: both M::i and N::i are visible
}
For another example,
namespace A {
int i;
}
namespace B {
int i;
int j;
namespace C {
namespace D {
using namespace A;
int j;
int k;
int a = i;
// B::i hides A::i
}
using namespace D;
int k = 89;
// no problem yet
int l = k;
// ambiguous: C::k or D::k
int m = i;
// B::i hides A::i
int n = j;
// D::j hides B::j
}
}
— end example ]
§ 10.3.4
169
5
If a namespace is extended (10.3.1) after a using-directive for that namespace is given, the additional members
of the extended namespace and the members of namespaces nominated by using-directives in the extending
namespace-definition can be used after the extending namespace-definition.
6
If name lookup finds a declaration for a name in two different namespaces, and the declarations do not
declare the same entity and do not declare functions, the use of the name is ill-formed. [ Note: In particular,
the name of a variable, function or enumerator does not hide the name of a class or enumeration declared in
a different namespace. For example,
namespace A {
class X { };
extern "C" int g();
extern "C++" int h();
}
namespace B {
void X(int);
extern "C" int g();
extern "C++" int h(int);
}
using namespace A;
using namespace B;
void f() {
X(1);
// error: name X found in two namespaces
g();
// OK: name g refers to the same entity
h();
// OK: overload resolution selects A::h
}
— end note ]
7
During overload resolution, all functions from the transitive search are considered for argument matching.
The set of declarations found by the transitive search is unordered. [ Note: In particular, the order in which
namespaces were considered and the relationships among the namespaces implied by the using-directives do
not cause preference to be given to any of the declarations found by the search.
— end note ] An ambiguity
exists if the best match finds two functions with the same signature, even if one is in a namespace reachable
through using-directives in the namespace of the other.101 [ Example:
namespace D {
int d1;
void f(char);
}
using namespace D;
int d1;
// OK: no conflict with D::d1
namespace E {
int e;
void f(int);
}
namespace D {
// namespace extension
int d2;
using namespace E;
void f(int);
}
void f() {
d1++;
// error: ambiguous ::d1 or D::d1?
::d1++;
// OK
D::d1++;
// OK
d2++;
// OK: D::d2
e++;
// OK: E::e
101) During name lookup in a class hierarchy, some ambiguities may be resolved by considering whether one member hides the
other along some paths (13.2). There is no such disambiguation when considering the set of names found as a result of following
using-directives.
§ 10.3.4
170
f(1);
// error: ambiguous: D::f(int) or E::f(int)?
f(’a’);
// OK: D::f(char)
}
— end example ]
10.4
The asm declaration
[dcl.asm]
1
An asm declaration has the form
asm-definition:
attribute-specifier-seqopt asm ( string-literal )
;
The asm declaration is conditionally-supported; its meaning is implementation-defined. The optional attribute-
specifier-seq in an asm-definition appertains to the asm declaration.
[Note: Typically it is used to pass
information through the implementation to an assembler.
— end note ]
10.5
Linkage specifications
[dcl.link]
1
All function types, function names with external linkage, and variable names with external linkage have a
language linkage. [ Note: Some of the properties associated with an entity with language linkage are specific
to each implementation and are not described here. For example, a particular language linkage may be
associated with a particular form of representing names of objects and functions with external linkage, or
with a particular calling convention, etc.
— end note ] The default language linkage of all function types,
function names, and variable names is C++ language linkage. Two function types with different language
linkages are distinct types even if they are otherwise identical.
2
Linkage (6.5) between C++ and non-C++ code fragments can be achieved using a linkage-specification:
linkage-specification:
extern string-literal { declaration-seqopt }
extern string-literal declaration
The string-literal indicates the required language linkage. This document specifies the semantics for the
string-literals "C" and "C++". Use of a string-literal other than "C" or "C++" is conditionally-supported,
with implementation-defined semantics. [Note: Therefore, a linkage-specification with a string-literal that
is unknown to the implementation requires a diagnostic.
— end note ] [Note: It is recommended that the
spelling of the string-literal be taken from the document defining that language. For example, Ada (not ADA)
and Fortran or FORTRAN, depending on the vintage. — end note ]
3
Every implementation shall provide for linkage to functions written in the C programming language, "C",
and linkage to C++ functions, "C++". [ Example:
complex sqrt(complex);
// C++ linkage by default
extern "C" {
double sqrt(double);
// C linkage
}
— end example ]
4
Linkage specifications nest. When linkage specifications nest, the innermost one determines the language
linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in
namespace scope (6.3). In a linkage-specification, the specified language linkage applies to the function types
of all function declarators, function names with external linkage, and variable names with external linkage
declared within the linkage-specification. [ Example:
extern "C"
// the name f1 and its function type have C language linkage;
void f1(void(*pf)(int));
// pf is a pointer to a C function
extern "C" typedef void FUNC();
FUNC f2;
// the name f2 has C++ language linkage and the
// function’s type has C language linkage
extern "C" FUNC f3;
// the name of function f3 and the function’s type have C language linkage
void (*pf2)(FUNC*);
// the name of the variable pf2 has C++ linkage and the type
// of pf2 is “pointer to C++ function that takes one parameter of type
// pointer to C function”
extern "C" {
static void f4();
// the name of the function f4 has internal linkage (not C language linkage)
§ 10.5
171

 

 

 

 

 

 

 

Content      ..     4      5      6      7     ..