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

 

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

 

Search            copyright infringement  

 

 

 

 

 

 

 

 

 

 

 

Content      ..     5      6      7      8     ..

 

 

 

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

 

 

// and the function’s type has C language linkage.
}
extern "C" void f5() {
extern void f4();
// OK: Name linkage (internal) and function type linkage (C language linkage)
// obtained from previous declaration.
}
extern void f4();
// OK: Name linkage (internal) and function type linkage (C language linkage)
// obtained from previous declaration.
void f6() {
extern void f4();
// OK: Name linkage (internal) and function type linkage (C language linkage)
// obtained from previous declaration.
}
— end example ] A C language linkage is ignored in determining the language linkage of the names of class
members and the function type of class member functions. [ Example:
extern "C" typedef void FUNC_c();
class C {
void mf1(FUNC_c*);
// the name of the function mf1 and the member function’s type have
// C++ language linkage; the parameter has type “pointer to C function”
FUNC_c mf2;
// the name of the function mf2 and the member function’s type have
// C++ language linkage
static FUNC_c* q;
// the name of the data member q has C++ language linkage and
// the data member’s type is “pointer to C function”
};
extern "C" {
class X {
void mf();
// the name of the function mf and the member function’s type have
// C++ language linkage
void mf2(void(*)());
// the name of the function mf2 has C++ language linkage;
// the parameter has type “pointer to C function”
};
}
— end example ]
5
If two declarations declare functions with the same name and parameter-type-list (11.3.5) to be members of
the same namespace or declare objects with the same name to be members of the same namespace and the
declarations give the names different language linkages, the program is ill-formed; no diagnostic is required
if the declarations appear in different translation units. Except for functions with C++ linkage, a function
declaration without a linkage specification shall not precede the first linkage specification for that function.
A function can be declared without a linkage specification after an explicit linkage specification has been
seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.
6
At most one function with a particular name can have C language linkage. Two declarations for a function
with C language linkage with the same function name (ignoring the namespace names that qualify it) that
appear in different namespace scopes refer to the same function. Two declarations for a variable with C
language linkage with the same name (ignoring the namespace names that qualify it) that appear in different
namespace scopes refer to the same variable. An entity with C language linkage shall not be declared with
the same name as a variable in global scope, unless both declarations denote the same entity; no diagnostic is
required if the declarations appear in different translation units. A variable with C language linkage shall not
be declared with the same name as a function with C language linkage (ignoring the namespace names that
qualify the respective names); no diagnostic is required if the declarations appear in different translation
units. [Note: Only one definition for an entity with a given name with C language linkage may appear in
the program (see 6.2); this implies that such an entity must not be defined in more than one namespace
scope. — end note ]
[ Example:
int x;
§ 10.5
172
namespace A {
extern "C" int f();
extern "C" int g() { return 1; }
extern "C" int h();
extern "C" int x();
// ill-formed: same name as global-space object x
}
namespace B {
extern "C" int f();
// A::f and B::f refer to the same function
extern "C" int g() { return 1; }
// ill-formed, the function g with C language linkage has two definitions
}
int A::f() { return 98; }
// definition for the function f with C language linkage
extern "C" int h() { return 97; }
// definition for the function h with C language linkage
// A::h and ::h refer to the same function
— end example ]
7
A declaration directly contained in a linkage-specification is treated as if it contains the extern specifier (10.1.1)
for the purpose of determining the linkage of the declared name and whether it is a definition. Such a
declaration shall not specify a storage class. [ Example:
extern "C" double f();
static double f();
// error
extern "C" int i;
// declaration
extern "C" {
int i;
// definition
}
extern "C" static void g();
// error
— end example ]
8
[Note: Because the language linkage is part of a function type, when indirecting through a pointer to C
function, the function to which the resulting lvalue refers is considered a C function.
— end note ]
9
Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages
is implementation-defined and language-dependent. Only where the object layout strategies of two language
implementations are similar enough can such linkage be achieved.
10.6
Attributes
[dcl.attr]
10.6.1
Attribute syntax and semantics
[dcl.attr.grammar]
1
Attributes specify additional information for various source constructs such as types, variables, names, blocks,
or translation units.
attribute-specifier-seq:
attribute-specifier-seqopt attribute-specifier
attribute-specifier:
[ [ attribute-using-prefixopt attribute-list ] ]
alignment-specifier
alignment-specifier:
alignas ( type-id ...opt )
alignas ( constant-expression ...opt )
attribute-using-prefix:
using attribute-namespace :
attribute-list:
attributeopt
attribute-list , attributeopt
attribute ...
attribute-list , attribute ...
attribute:
attribute-token attribute-argument-clauseopt
attribute-token:
identifier
attribute-scoped-token
§ 10.6.1
173
attribute-scoped-token:
attribute-namespace :: identifier
attribute-namespace:
identifier
attribute-argument-clause:
( balanced-token-seqopt )
balanced-token-seq:
balanced-token
balanced-token-seq balanced-token
balanced-token:
( balanced-token-seqopt )
[ balanced-token-seqopt ]
{ balanced-token-seqopt }
any token other than a parenthesis, a bracket, or a brace
2
If an attribute-specifier contains an attribute-using-prefix, the attribute-list following that attribute-using-prefix
shall not contain an attribute-scoped-token and every attribute-token in that attribute-list is treated as if
its identifier were prefixed with N::, where N is the attribute-namespace specified in the attribute-using-
prefix.
[Note: This rule imposes no constraints on how an attribute-using-prefix affects the tokens in an
attribute-argument-clause.
— end note ] [ Example:
[[using CC: opt(1), debug]]
// same as [[CC::opt(1), CC::debug]]
void f() {}
[[using CC: opt(1)]] [[CC::debug]]
// same as [[CC::opt(1)]] [[CC::debug]]
void g() {}
[[using CC: CC::opt(1)]]
// error: cannot combine using and scoped attribute token
void h() {}
— end example ]
3
[ Note: For each individual attribute, the form of the balanced-token-seq will be specified.
— end note ]
4
In an attribute-list, an ellipsis may appear only if that attribute’s specification permits it. An attribute
followed by an ellipsis is a pack expansion (17.6.3). An attribute-specifier that contains no attributes has no
effect. The order in which the attribute-tokens appear in an attribute-list is not significant. If a keyword (5.11)
or an alternative token (5.5) that satisfies the syntactic requirements of an identifier (5.10) is contained
in an attribute-token, it is considered an identifier. No name lookup (6.4) is performed on any of the
identifiers contained in an attribute-token. The attribute-token determines additional requirements on the
attribute-argument-clause (if any).
5
Each attribute-specifier-seq is said to appertain to some entity or statement, identified by the syntactic context
where it appears (Clause 9, Clause 10, Clause 11). If an attribute-specifier-seq that appertains to some
entity or statement contains an attribute or alignment-specifier that is not allowed to apply to that entity or
statement, the program is ill-formed. If an attribute-specifier-seq appertains to a friend declaration (14.3), that
declaration shall be a definition. No attribute-specifier-seq shall appertain to an explicit instantiation (17.8.2).
6
For an attribute-token (including an attribute-scoped-token) not specified in this document, the behavior is
implementation-defined. Any attribute-token that is not recognized by the implementation is ignored. [ Note:
Each implementation should choose a distinctive name for the attribute-namespace in an attribute-scoped-token.
— end note ]
7
Two consecutive left square bracket tokens shall appear only when introducing an attribute-specifier or within
the balanced-token-seq of an attribute-argument-clause. [ Note: If two consecutive left square brackets appear
where an attribute-specifier is not allowed, the program is ill-formed even if the brackets match an alternative
grammar production. — end note ]
[ Example:
int p[10];
void f() {
int x = 42, y[5];
int(p[[x] { return x; }()]);
// error: invalid attribute on a nested declarator-id and
// not a function-style cast of an element of p.
y[[] { return 2; }()] = 2;
// error even though attributes are not allowed in this context.
int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute.
}
— end example ]
§ 10.6.1
174
10.6.2
Alignment specifier
[dcl.align]
1
An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a
bit-field, a function parameter, or an exception-declaration (18.3). An alignment-specifier may also be applied
to the declaration or definition of a class (in an elaborated-type-specifier (10.1.7.3) or class-head (Clause
12), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or
enum-head, respectively (10.2)). An alignment-specifier with an ellipsis is a pack expansion (17.6.3).
2
When the alignment-specifier is of the form alignas( constant-expression ):
(2.1)
the constant-expression shall be an integral constant expression
(2.2)
if the constant expression does not evaluate to an alignment value (6.6.5), or evaluates to an extended
alignment and the implementation does not support that alignment in the context of the declaration,
the program is ill-formed.
3
An alignment-specifier of the form alignas( type-id ) has the same effect as alignas(alignof( type-
id )) (8.5.2.6).
4
The alignment requirement of an entity is the strictest nonzero alignment specified by its alignment-specifier s,
if any; otherwise, the alignment-specifier s have no effect.
5
The combined effect of all alignment-specifiers in a declaration shall not specify an alignment that is less
strict than the alignment that would be required for the entity being declared if all alignment-specifiers
appertaining to that entity were omitted. [ Example:
struct alignas(8) S {};
struct alignas(1) U {
S s;
};
// error: U specifies an alignment that is less strict than if the alignas(1) were omitted.
— end example ]
6
If the defining declaration of an entity has an alignment-specifier , any non-defining declaration of that entity
shall either specify equivalent alignment or have no alignment-specifier. Conversely, if any declaration of
an entity has an alignment-specifier, every defining declaration of that entity shall specify an equivalent
alignment. No diagnostic is required if declarations of an entity have different alignment-specifier s in different
translation units. [ Example:
// Translation unit #1:
struct S { int x; } s, *p = &s;
// Translation unit #2:
struct alignas(16) S;
// error: definition of S lacks alignment, no diagnostic required
extern S* p;
— end example ]
7
[Example: An aligned buffer with an alignment requirement of A and holding N elements of type T can be
declared as:
alignas(T) alignas(A) T buffer[N];
Specifying alignas(T) ensures that the final requested alignment will not be weaker than alignof(T), and
therefore the program will not be ill-formed.
— end example ]
8
[ Example:
alignas(double) void f();
// error: alignment applied to function
alignas(double) unsigned char c[sizeof(double)];
// array of characters, suitably aligned for a double
extern unsigned char c[sizeof(double)];
// no alignas necessary
alignas(float)
extern unsigned char c[sizeof(double)];
// error: different alignment in declaration
— end example ]
10.6.3
Carries dependency attribute
[dcl.attr.depend]
1
The attribute-token carries_dependency specifies dependency propagation into and out of functions. It shall
appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute
may be applied to the declarator-id of a parameter-declaration in a function declaration or lambda, in which
case it specifies that the initialization of the parameter carries a dependency to (6.8.2) each lvalue-to-rvalue
§ 10.6.3
175
conversion (7.1) of that object. The attribute may also be applied to the declarator-id of a function declaration,
in which case it specifies that the return value, if any, carries a dependency to the evaluation of the function
call expression.
2
The first declaration of a function shall specify the carries_dependency attribute for its declarator-id if any
declaration of the function specifies the carries_dependency attribute. Furthermore, the first declaration of
a function shall specify the carries_dependency attribute for a parameter if any declaration of that function
specifies the carries_dependency attribute for that parameter. If a function or one of its parameters is
declared with the carries_dependency attribute in its first declaration in one translation unit and the
same function or one of its parameters is declared without the carries_dependency attribute in its first
declaration in another translation unit, the program is ill-formed, no diagnostic required.
3
[ Note: The carries_dependency attribute does not change the meaning of the program, but may result in
generation of more efficient code.
— end note ]
4
[ Example:
/∗ Translation unit A. ∗/
struct foo { int* a; int* b; };
std::atomic<struct foo *> foo_head[10];
int foo_array[10][10];
[[carries_dependency]] struct foo* f(int i) {
return foo_head[i].load(memory_order::consume);
}
int g(int* x, int* y [[carries_dependency]]) {
return kill_dependency(foo_array[*x][*y]);
}
/∗ Translation unit B. ∗/
[[carries_dependency]] struct foo* f(int i);
int g(int* x, int* y [[carries_dependency]]);
int c = 3;
void h(int i) {
struct foo* p;
p = f(i);
do_something_with(g(&c, p->a));
do_something_with(g(p->a, &c));
}
The carries_dependency attribute on function f means that the return value carries a dependency out of
f, so that the implementation need not constrain ordering upon return from f. Implementations of f and
its caller may choose to preserve dependencies instead of emitting hardware memory ordering instructions
(a.k.a. fences). Function g’s second parameter has a carries_dependency attribute, but its first parameter
does not. Therefore, function h’s first call to g carries a dependency into g, but its second call does not. The
implementation might need to insert a fence prior to the second call to g.
— end example ]
10.6.4
Deprecated attribute
[dcl.attr.deprecated]
1
The attribute-token deprecated can be used to mark names and entities whose use is still allowed, but is
discouraged for some reason. [Note: In particular, deprecated is appropriate for names and entities that
are deemed obsolescent or unsafe.
— end note ] It shall appear at most once in each attribute-list. An
attribute-argument-clause may be present and, if present, it shall have the form:
( string-literal
)
[ Note: The string-literal in the attribute-argument-clause could be used to explain the rationale for deprecation
and/or to suggest a replacing entity.
— end note ]
2
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data
member, a function, a namespace, an enumeration, an enumerator, or a template specialization.
§ 10.6.4
176
3
A name or entity declared without the deprecated attribute can later be redeclared with the attribute and
vice-versa. [ Note: Thus, an entity initially declared without the attribute can be marked as deprecated by
a subsequent redeclaration. However, after an entity is marked as deprecated, later redeclarations do not
un-deprecate the entity.
— end note ] Redeclarations using different forms of the attribute (with or without
the attribute-argument-clause or with different attribute-argument-clauses) are allowed.
4
[Note: Implementations may use the deprecated attribute to produce a diagnostic message in case the
program refers to a name or entity other than to declare it, after a declaration that specifies the attribute. The
diagnostic message may include the text provided within the attribute-argument-clause of any deprecated
attribute applied to the name or entity.
— end note ]
10.6.5
Fallthrough attribute
[dcl.attr.fallthrough]
1
The attribute-token fallthrough may be applied to a null statement (9.2); such a statement is a fallthrough
statement. The attribute-token fallthrough shall appear at most once in each attribute-list and no attribute-
argument-clause shall be present. A fallthrough statement may only appear within an enclosing switch
statement (9.4.2). The next statement that would be executed after a fallthrough statement shall be a
labeled statement whose label is a case label or default label for the same switch statement. The program is
ill-formed if there is no such statement.
2
[ Note: The use of a fallthrough statement is intended to suppress a warning that an implementation might
otherwise issue for a case or default label that is reachable from another case or default label along some
path of execution. Implementations should issue a warning if a fallthrough statement is not dynamically
reachable.
— end note ]
3
[ Example:
void f(int n) {
void g(), h(), i();
switch (n) {
case 1:
case 2:
g();
[[fallthrough]];
case 3:
// warning on fallthrough discouraged
h();
case 4:
// implementation may warn on fallthrough
i();
[[fallthrough]];
// ill-formed
}
}
— end example ]
10.6.6
Maybe unused attribute
[dcl.attr.unused]
1
The attribute-token maybe_unused indicates that a name or entity is possibly intentionally unused. It shall
appear at most once in each attribute-list and no attribute-argument-clause shall be present.
2
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data
member, a function, an enumeration, or an enumerator.
3
[Note: For an entity marked maybe_unused, implementations should not emit a warning that the entity is
unused, or that the entity is used despite the presence of the attribute.
— end note ]
4
A name or entity declared without the maybe_unused attribute can later be redeclared with the attribute
and vice versa. An entity is considered marked after the first declaration that marks it.
5
[ Example:
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
[[maybe_unused]] bool thing2) {
[[maybe_unused]] bool b = thing1 && thing2;
assert(b);
}
Implementations should not warn that b is unused, whether or not NDEBUG is defined.
— end example ]
§ 10.6.6
177
10.6.7
Nodiscard attribute
[dcl.attr.nodiscard]
1
The attribute-token nodiscard may be applied to the declarator-id in a function declaration or to the
declaration of a class or enumeration. It shall appear at most once in each attribute-list and no attribute-
argument-clause shall be present.
2
[ Note: A nodiscard call is a function call expression that calls a function previously declared nodiscard, or
whose return type is a possibly cv-qualified class or enumeration type marked nodiscard. Appearance of
a nodiscard call as a potentially-evaluated discarded-value expression (8.2) is discouraged unless explicitly
cast to void. Implementations should issue a warning in such cases. This is typically because discarding the
return value of a nodiscard call has surprising consequences.
— end note ]
3
[ Example:
struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
enable_missile_safety_mode(); // warning encouraged
launch_missiles();
}
error_info &foo();
void f() { foo(); }
// warning not encouraged: not a nodiscard call, because neither
// the (reference) return type nor the function is declared nodiscard
— end example ]
10.6.8
Noreturn attribute
[dcl.attr.noreturn]
1
The attribute-token noreturn specifies that a function does not return. It shall appear at most once in
each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to
the declarator-id in a function declaration. The first declaration of a function shall specify the noreturn
attribute if any declaration of that function specifies the noreturn attribute. If a function is declared with
the noreturn attribute in one translation unit and the same function is declared without the noreturn
attribute in another translation unit, the program is ill-formed, no diagnostic required.
2
If a function f is called where f was previously declared with the noreturn attribute and f eventually returns,
the behavior is undefined.
[Note: The function may terminate by throwing an exception.
— end note ]
[Note: Implementations should issue a warning if a function marked [[noreturn]] might return.
— end
note ]
3
[ Example:
[[ noreturn ]] void f() {
throw "error";
// OK
}
[[ noreturn ]] void q(int i) {
// behavior is undefined if called with an argument <= 0
if (i > 0)
throw "positive";
}
— end example ]
§ 10.6.8
178
11
Declarators
[dcl.decl]
1
A declarator declares a single variable, function, or type, within a declaration. The init-declarator-list
appearing in a declaration is a comma-separated sequence of declarators, each of which can have an initializer.
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator initializeropt
declarator requires-clause
2
The three components of a simple-declaration are the attributes (10.6), the specifiers (decl-specifier-seq; 10.1)
and the declarators (init-declarator-list). The specifiers indicate the type, storage class or other properties of
the entities being declared. The declarators specify the names of these entities and (optionally) modify the
type of the specifiers with operators such as * (pointer to) and () (function returning). Initial values can
also be specified in a declarator; initializers are discussed in 11.6 and 15.6.
3
Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself. [Note: A
declaration with several declarators is usually equivalent to the corresponding sequence of declarations each
with a single declarator. That is
T D1, D2, ... Dn;
is usually equivalent to
T D1; T D2; ... T Dn;
where T is a decl-specifier-seq and each Di is an init-declarator. One exception is when a name introduced by
one of the declarator s hides a type name used by the decl-specifier s, so that when the same decl-specifier s are
used in a subsequent declaration, they do not have the same meaning, as in
struct S { ... };
S S, T;
// declare two instances of struct S
which is not equivalent to
struct S { ... };
S S;
S T;
// error
Another exception is when T is auto (10.1.7.4), for example:
auto i = 1, j = 2.0;
// error: deduced types for i and j do not match
as opposed to
auto i = 1;
// OK: i deduced to have type int
auto j = 2.0;
// OK: j deduced to have type double
— end note ]
4
The optional requires-clause (Clause 17) in an init-declarator or member-declarator shall not be present when
the declarator does not declare a function (11.3.5). When present after a declarator, the requires-clause
is called the trailing requires-clause. The trailing requires-clause introduces the constraint-expression that
results from interpreting its constraint-logical-or-expression as a constraint-expression. [ Example:
void f1(int a) requires true;
// OK
auto f2(int a) -> bool requires true;
// OK
auto f3(int a) requires true -> bool;
// error: requires-clause precedes trailing-return-type
void (*pf)() requires true;
// error: constraint on a variable
void g(int (*)() requires true);
// error: constraint on a parameter-declaration
auto* p = new void(*)(char) requires true;
// error: not a function declaration
— end example ]
5
Declarators have the syntax
Declarators
179
declarator:
ptr-declarator
noptr-declarator parameters-and-qualifiers trailing-return-type
ptr-declarator:
noptr-declarator
ptr-operator ptr-declarator
noptr-declarator:
declarator-id attribute-specifier-seqopt
noptr-declarator parameters-and-qualifiers
noptr-declarator [ constant-expressionopt ] attribute-specifier-seqopt
( ptr-declarator )
parameters-and-qualifiers:
( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt
trailing-return-type:
-> type-id
ptr-operator:
* attribute-specifier-seqopt cv-qualifier-seqopt
& attribute-specifier-seqopt
&& attribute-specifier-seqopt
nested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt
cv-qualifier-seq:
cv-qualifier cv-qualifier-seqopt
cv-qualifier:
const
volatile
ref-qualifier:
&
&&
declarator-id:
...opt id-expression
11.1
Type names
[dcl.name]
1
To specify type conversions explicitly, and as an argument of sizeof, alignof, new, or typeid, the name of
a type shall be specified. This can be done with a type-id, which is syntactically a declaration for a variable
or function of that type that omits the name of the entity.
type-id:
type-specifier-seq abstract-declaratoropt
defining-type-id:
defining-type-specifier-seq abstract-declaratoropt
abstract-declarator:
ptr-abstract-declarator
noptr-abstract-declaratoropt parameters-and-qualifiers trailing-return-type
abstract-pack-declarator
ptr-abstract-declarator:
noptr-abstract-declarator
ptr-operator ptr-abstract-declaratoropt
noptr-abstract-declarator:
noptr-abstract-declaratoropt parameters-and-qualifiers
noptr-abstract-declaratoropt [ constant-expressionopt ] attribute-specifier-seqopt
( ptr-abstract-declarator )
abstract-pack-declarator:
noptr-abstract-pack-declarator
ptr-operator abstract-pack-declarator
§ 11.1
180
noptr-abstract-pack-declarator:
noptr-abstract-pack-declarator parameters-and-qualifiers
noptr-abstract-pack-declarator [ constant-expressionopt ] attribute-specifier-seqopt
It is possible to identify uniquely the location in the abstract-declarator where the identifier would appear if
the construction were a declarator in a declaration. The named type is then the same as the type of the
hypothetical identifier. [ Example:
int
// int i
int *
// int *pi
int *[3]
// int *p[3]
int (*)[3]
// int (*p3i)[3]
int *()
// int *f()
int (*)(double)
// int (*pf)(double)
name respectively the types “int”, “pointer to int”, “array of 3 pointers to int”, “pointer to array of 3 int”,
“function of (no parameters) returning pointer to int”, and “pointer to a function of (double) returning int”.
— end example ]
2
A type can also be named (often more easily) by using a typedef (10.1.3).
11.2
Ambiguity resolution
[dcl.ambig.res]
1
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 9.8
can also occur in the context of a declaration. In that context, the choice is between a function declaration
with a redundant set of parentheses around a parameter name and an object declaration with a function-style
cast as the initializer. Just as for the ambiguities mentioned in 9.8, the resolution is to consider any construct
that could possibly be a declaration a declaration. [Note: A declaration can be explicitly disambiguated
by adding parentheses around the argument. The ambiguity can be avoided by use of copy-initialization or
list-initialization syntax, or by use of a non-function-style cast.
— end note ] [ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a));
// function declaration
S x(int());
// function declaration
S y((int(a)));
// object declaration
S y((int)a);
// object declaration
S z = int(a);
// object declaration
}
— end example ]
2
An ambiguity can arise from the similarity between a function-style cast and a type-id. The resolution is that
any construct that could possibly be a type-id in its syntactic context shall be considered a type-id. [ Example:
template <class T> struct X {};
template <int N> struct Y {};
X<int()> a;
// type-id
X<int(1)> b;
// expression (ill-formed)
Y<int()> c;
// type-id (ill-formed)
Y<int(1)> d;
// expression
void foo(signed char a) {
sizeof(int());
// type-id (ill-formed)
sizeof(int(a));
// expression
sizeof(int(unsigned(a)));
// type-id (ill-formed)
(int())+1;
// type-id (ill-formed)
(int(a))+1;
// expression
(int(unsigned(a)))+1;
// type-id (ill-formed)
}
— end example ]
§ 11.2
181
3
Another ambiguity arises in a parameter-declaration-clause when a type-name is nested in parentheses. In this
case, the choice is between the declaration of a parameter of type pointer to function and the declaration of a
parameter with redundant parentheses around the declarator-id. The resolution is to consider the type-name
as a simple-type-specifier rather than a declarator-id. [ Example:
class C { };
void f(int(C)) { }
// void f(int(*fp)(C c)) { }
// not: void f(int C) { }
int g(C);
void foo() {
f(1);
// error: cannot convert 1 to function pointer
f(g);
// OK
}
For another example,
class C { };
void h(int *(C[10]));
// void h(int *(*_fp)(C _parm[10]));
// not: void h(int *C[10]);
— end example ]
11.3
Meaning of declarators
[dcl.meaning]
1
A declarator contains exactly one declarator-id; it names the identifier that is declared. An unqualified-id
occurring in a declarator-id shall be a simple identifier except for the declaration of some special functions (15.1,
15.3, 15.4, 16.5) and for the declaration of template specializations or partial specializations (17.8). When the
declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace
to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that
namespace (10.3.1)) or to a specialization thereof; the member shall not merely have been introduced by
a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the
declarator-id. The nested-name-specifier of a qualified declarator-id shall not begin with a decltype-specifier.
[ Note: If the qualifier is the global :: scope resolution operator, the declarator-id refers to a name declared
in the global namespace scope.
— end note ] The optional attribute-specifier-seq following a declarator-id
appertains to the entity that is declared.
2
A static, thread_local, extern, mutable, friend, inline, virtual, constexpr, explicit, or typedef
specifier applies directly to each declarator-id in an init-declarator-list or member-declarator-list; the type
specified for each declarator-id depends on both the decl-specifier-seq and its declarator.
3
Thus, a declaration of a particular identifier has the form
T D
where T is of the form attribute-specifier-seqopt decl-specifier-seq and D is a declarator. Following is a recursive
procedure for determining the type specified for the contained declarator-id by such a declaration.
4
First, the decl-specifier-seq determines a type. In a declaration
T D
the decl-specifier-seq T determines the type T. [ Example: In the declaration
int unsigned i;
the type specifiers int unsigned determine the type “unsigned int” (10.1.7.2).
— end example ]
5
In a declaration attribute-specifier-seqopt T D where D is an unadorned identifier the type of this identifier is
“T”.
6
In a declaration T D where D has the form
( D1 )
the type of the contained declarator-id is the same as that of the contained declarator-id in the declaration
T D1
Parentheses do not alter the type of the embedded declarator-id, but they can alter the binding of complex
declarators.
§ 11.3
182
11.3.1
Pointers
[dcl.ptr]
1
In a declaration T D where D has the form
* attribute-specifier-seqopt cv-qualifier-seqopt D1
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the
identifier of D is “derived-declarator-type-list cv-qualifier-seq pointer to T”. The cv-qualifiers apply to the
pointer and not to the object pointed to. Similarly, the optional attribute-specifier-seq (10.6.1) appertains to
the pointer and not to the object pointed to.
2
[ Example: The declarations
const int ci = 10, *pc = &ci, *const cpc = pc, **ppc;
int i, *p, *const cp = &i;
declare ci, a constant integer; pc, a pointer to a constant integer; cpc, a constant pointer to a constant
integer; ppc, a pointer to a pointer to a constant integer; i, an integer; p, a pointer to integer; and cp, a
constant pointer to integer. The value of ci, cpc, and cp cannot be changed after initialization. The value of
pc can be changed, and so can the object pointed to by cp. Examples of some correct operations are
i = ci;
*cp = ci;
pc++;
pc = cpc;
pc = p;
ppc = &pc;
Examples of ill-formed operations are
ci = 1;
// error
ci++;
// error
*pc = 2;
// error
cp = &ci;
// error
cpc++;
// error
p = pc;
// error
ppc = &p;
// error
Each is unacceptable because it would either change the value of an object declared const or allow it to be
changed through a cv-unqualified pointer later, for example:
*ppc = &ci;
// OK, but would make p point to ci because of previous error
*p = 5;
// clobber ci
— end example ]
3
See also 8.5.18 and 11.6.
4
[Note: Forming a pointer to reference type is ill-formed; see 11.3.2. Forming a function pointer type
is ill-formed if the function type has cv-qualifiers or a ref-qualifier; see 11.3.5. Since the address of a
bit-field (12.2.4) cannot be taken, a pointer can never point to a bit-field.
— end note ]
11.3.2
References
[dcl.ref]
1
In a declaration T D where D has either of the forms
& attribute-specifier-seqopt D1
&& attribute-specifier-seqopt D1
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the
identifier of D is “derived-declarator-type-list reference to T”. The optional attribute-specifier-seq appertains
to the reference type. Cv-qualified references are ill-formed except when the cv-qualifiers are introduced
through the use of a typedef-name (10.1.3, 17.1) or decltype-specifier (10.1.7.2), in which case the cv-qualifiers
are ignored. [ Example:
typedef int& A;
const A aref = 3;
// ill-formed; lvalue reference to non-const initialized with rvalue
The type of aref is “lvalue reference to int”, not “lvalue reference to const int”.
— end example ] [ Note:
A reference can be thought of as a name of an object.
— end note ] A declarator that specifies the type
“reference to cv void” is ill-formed.
§ 11.3.2
183
2
A reference type that is declared using & is called an lvalue reference, and a reference type that is declared
using && is called an rvalue reference. Lvalue references and rvalue references are distinct types. Except
where explicitly noted, they are semantically equivalent and commonly referred to as references.
3
[ Example:
void f(double& a) { a += 3.14; }
// ...
double d = 0;
f(d);
declares a to be a reference parameter of f so the call f(d) will add 3.14 to d.
int v[20];
// ...
int& g(int i) { return v[i]; }
// ...
g(3) = 7;
declares the function g() to return a reference to an integer so g(3)=7 will assign
7
to the fourth element of
the array v. For another example,
struct link {
link* next;
};
link* first;
void h(link*& p) {
// p is a reference to pointer
p->next = first;
first = p;
p = 0;
}
void k() {
link* q = new link;
h(q);
}
declares p to be a reference to a pointer to link so h(q) will leave q with the value zero. See also 11.6.3.
— end example ]
4
It is unspecified whether or not a reference requires storage (6.6.4).
5
There shall be no references to references, no arrays of references, and no pointers to references. The
declaration of a reference shall contain an initializer (11.6.3) except when the declaration contains an explicit
extern specifier (10.1.1), is a class member (12.2) declaration within a class definition, or is the declaration
of a parameter or a return type (11.3.5); see 6.1. A reference shall be initialized to refer to a valid object or
function. [ Note: In particular, a null reference cannot exist in a well-defined program, because the only way
to create such a reference would be to bind it to the “object” obtained by indirection through a null pointer,
which causes undefined behavior. As described in 12.2.4, a reference cannot be bound directly to a bit-field.
— end note ]
6
If a typedef-name (10.1.3, 17.1) or a decltype-specifier (10.1.7.2) denotes a type TR that is a reference to a type
T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an
attempt to create the type “rvalue reference to cv TR” creates the type TR. [Note: This rule is known as
reference collapsing.
— end note ] [ Example:
int i;
typedef int& LRI;
typedef int&& RRI;
LRI& r1 = i;
// r1 has the type int&
const LRI& r2 = i;
// r2 has the type int&
const LRI&& r3 = i;
// r3 has the type int&
RRI& r4 = i;
// r4 has the type int&
RRI&& r5 = 5;
// r5 has the type int&&
§ 11.3.2
184
decltype(r2)& r6 = i;
// r6 has the type int&
decltype(r2)&& r7 = i;
// r7 has the type int&
— end example ]
7
[ Note: Forming a reference to function type is ill-formed if the function type has cv-qualifier s or a ref-qualifier ;
see 11.3.5.
— end note ]
11.3.3
Pointers to members
[dcl.mptr]
1
In a declaration T D where D has the form
nested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt D1
and the nested-name-specifier denotes a class, and the type of the identifier in the declaration T D1 is “derived-
declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list cv-qualifier-seq
pointer to member of class nested-name-specifier of type T”. The optional attribute-specifier-seq (10.6.1)
appertains to the pointer-to-member.
2
[ Example:
struct X {
void f(int);
int a;
};
struct Y;
int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;
double X::* pmd;
char Y::* pmc;
declares pmi, pmf, pmd and pmc to be a pointer to a member of X of type int, a pointer to a member of X of
type void(int), a pointer to a member of X of type double and a pointer to a member of Y of type char
respectively. The declaration of pmd is well-formed even though X has no members of type double. Similarly,
the declaration of pmc is well-formed even though Y is an incomplete type. pmi and pmf can be used like
this:
X obj;
// ...
obj.*pmi = 7;
// assign 7 to an integer member of obj
(obj.*pmf)(7);
// call a function member of obj with the argument 7
— end example ]
3
A pointer to member shall not point to a static member of a class (12.2.3), a member with reference type, or
“cv void”.
[ Note: See also 8.5.2 and 8.5.4. The type “pointer to member” is distinct from the type “pointer”, that is, a
pointer to member is declared only by the pointer-to-member declarator syntax, and never by the pointer
declarator syntax. There is no “reference-to-member” type in C++.
— end note ]
11.3.4
Arrays
[dcl.array]
1
In a declaration T D where D has the form
D1 [ constant-expressionopt ] attribute-specifier-seqopt
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the
identifier of D is an array type; if the type of the identifier of D contains the auto type-specifier, the program
is ill-formed. T is called the array element type; this type shall not be a reference type, cv void, a function
type or an abstract class type. If the constant-expression (8.6) is present, it shall be a converted constant
expression of type std::size_t and its value shall be greater than zero. The constant expression specifies
the bound of (number of elements in) the array. If the value of the constant expression is N, the array has N
elements numbered 0 to N-1, and the type of the identifier of D is “derived-declarator-type-list array of N T”.
An object of array type contains a contiguously allocated non-empty set of N subobjects of type T. Except as
noted below, if the constant expression is omitted, the type of the identifier of D is “derived-declarator-type-list
array of unknown bound of T”, an incomplete object type. The type “derived-declarator-type-list array of N
T” is a different type from the type “derived-declarator-type-list array of unknown bound of T”, see 6.7. Any
§ 11.3.4
185
type of the form “cv-qualifier-seq array of N T” is adjusted to “array of N cv-qualifier-seq T”, and similarly for
“array of unknown bound of T”. The optional attribute-specifier-seq appertains to the array. [ Example:
typedef int A[5], AA[2][3];
typedef const A CA;
// type is “array of 5 const int”
typedef const AA CAA;
// type is “array of 2 array of 3 const int”
— end example ] [ Note: An “array of N cv-qualifier-seq T” has cv-qualified type; see 6.7.3.
— end note ]
2
An array can be constructed from one of the fundamental types (except void), from a pointer, from a pointer
to member, from a class, from an enumeration type, or from another array.
3
When several “array of” specifications are adjacent, a multidimensional array type is created; only the first of
the constant expressions that specify the bounds of the arrays may be omitted. In addition to declarations in
which an incomplete object type is allowed, an array bound may be omitted in some cases in the declaration
of a function parameter (11.3.5). An array bound may also be omitted when the declarator is followed by an
initializer (11.6) or when a declarator for a static data member is followed by a brace-or-equal-initializer (12.2).
In both cases the bound is calculated from the number of initial elements (say, N) supplied (11.6.1), and the
type of the identifier of D is “array of N T”. Furthermore, if there is a preceding declaration of the entity in
the same scope in which the bound was specified, an omitted array bound is taken to be the same as in that
earlier declaration, and similarly for the definition of a static data member of a class.
4
[ Example:
float fa[17], *afp[17];
declares an array of float numbers and an array of pointers to float numbers.
— end example ]
5
[ Example:
int x3d[3][5][7];
declares an array of three elements, each of which is an array of five elements, each of which is an array of
seven integers. The overall array can be viewed as a three-dimensional array of integers, with rank 3 × 5 × 7.
Any of the expressions x3d, x3d[i], x3d[i][j], x3d[i][j][k] can reasonably appear in an expression. The
expression x3d[i] is equivalent to *(x3d + i); in that expression, x3d is subject to the array-to-pointer
conversion (7.2) and is first converted to a pointer to a 2-dimensional array with rank 5 × 7 that points to
the first element of x3d. Then i is added, which on typical implementations involves multiplying i by the
length of the object to which the pointer points, which is sizeof(int)×5 × 7. The result of the addition
and indirection is an lvalue denoting the ith array element of x3d (an array of five arrays of seven integers).
If there is another subscript, the same argument applies again, so x3d[i][j] is an lvalue denoting the jth
array element of the ith array element of x3d (an array of seven integers), and x3d[i][j][k] is an lvalue
denoting the kth array element of the jth array element of the ith array element of x3d (an integer).
— end
example ]
[ Note: The first subscript in the declaration helps determine the amount of storage consumed by
an array but plays no other part in subscript calculations.
— end note ]
6
[ Example:
extern int x[10];
struct S {
static int y[10];
};
int x[];
// OK: bound is 10
int S::y[];
// OK: bound is 10
void f() {
extern int x[];
int i = sizeof(x);
// error: incomplete object type
}
— end example ]
7
[ Note: Conversions affecting expressions of array type are described in 7.2. Objects of array types cannot be
modified, see 8.2.1.
— end note ]
8
[ Note: Except where it has been declared for a class (16.5.5), the subscript operator [] is interpreted in such
a way that E1[E2] is identical to *((E1)+(E2)) (8.5.1.1). Because of the conversion rules that apply to +,
if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its
asymmetric appearance, subscripting is a commutative operation.
— end note ]
§ 11.3.4
186
11.3.5
Functions
[dcl.fct]
1
In a declaration T D where D has the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt
and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, the type
of the declarator-id in D is “derived-declarator-type-list noexceptopt function of (parameter-declaration-clause)
cv-qualifier-seqopt ref-qualifieropt returning T”, where the optional noexcept is present if and only if the
exception specification (18.4) is non-throwing. The optional attribute-specifier-seq appertains to the function
type.
2
In a declaration T D where D has the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-type
and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, T shall be
the single type-specifier auto. The type of the declarator-id in D is “derived-declarator-type-list noexceptopt
function of (parameter-declaration-clause) cv-qualifier-seqopt ref-qualifieropt returning U”, where U is the type
specified by the trailing-return-type, and where the optional noexcept is present if and only if the exception
specification is non-throwing. The optional attribute-specifier-seq appertains to the function type.
3
A type of either form is a function type.102
parameter-declaration-clause:
parameter-declaration-listopt ...opt
parameter-declaration-list , ...
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt
attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt = initializer-clause
The optional attribute-specifier-seq in a parameter-declaration appertains to the parameter.
4
The parameter-declaration-clause determines the arguments that can be specified, and their processing, when
the function is called. [ Note: The parameter-declaration-clause is used to convert the arguments specified on
the function call; see 8.5.1.2.
— end note ] If the parameter-declaration-clause is empty, the function takes
no arguments. A parameter list consisting of a single unnamed parameter of non-dependent type void is
equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cv void.
If the parameter-declaration-clause terminates with an ellipsis or a function parameter pack (17.6.3), the
number of arguments shall be equal to or greater than the number of parameters that do not have a default
argument and are not function parameter packs. Where syntactically correct and where “...” is not part of
an abstract-declarator, “, ...” is synonymous with “...”. [ Example: The declaration
int printf(const char*, ...);
declares a function that can be called with varying numbers and types of arguments.
printf("hello world");
printf("a=%d b=%d", a, b);
However, the first argument must be of a type that can be converted to a const char* — end example ]
[Note: The standard header <cstdarg> contains a mechanism for accessing arguments passed using the
ellipsis (see 8.5.1.2 and 21.11).
— end note ]
5
The type of a function is determined using the following rules. The type of each parameter (including
function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining
the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be
“pointer to T”. After producing the list of parameter types, any top-level cv-qualifier s modifying a parameter
type are deleted when forming the function type. The resulting list of transformed parameter types and
the presence or absence of the ellipsis or a function parameter pack is the function’s parameter-type-list.
102) As indicated by syntax, cv-qualifiers are a significant component in function return types.
§ 11.3.5
187
[ Note: This transformation does not affect the types of the parameters. For example, int(*)(const int p,
decltype(p)*) and int(*)(int, const int*) are identical types. — end note ]
6
A function type with a cv-qualifier-seq or a ref-qualifier (including a type named by typedef-name (10.1.3,
17.1)) shall appear only as:
(6.1)
the function type for a non-static member function,
(6.2)
the function type to which a pointer to member refers,
(6.3)
the top-level function type of a function typedef declaration or alias-declaration,
(6.4)
the type-id in the default argument of a type-parameter (17.1), or
(6.5)
the type-id of a template-argument for a type-parameter (17.3.1).
[ Example:
typedef int FIC(int) const;
FIC f;
// ill-formed: does not declare a member function
struct S {
FIC f;
// OK
};
FIC S::*pm = &S::f; // OK
— end example ]
7
The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top
of the function type. In the latter case, the cv-qualifiers are ignored.
[Note: A function type that has a
cv-qualifier-seq is not a cv-qualified type; there are no cv-qualified function types.
— end note ] [ Example:
typedef void F();
struct S {
const F f;
// OK: equivalent to: void f();
};
— end example ]
8
The return type, the parameter-type-list, the ref-qualifier, the cv-qualifier-seq, and the exception specification,
but not the default arguments (11.3.6) or the trailing requires-clause (Clause 11), are part of the function
type. [ Note: Function types are checked during the assignments and initializations of pointers to functions,
references to functions, and pointers to member functions.
— end note ]
9
[ Example: The declaration
int fseek(FILE*, long, int);
declares a function taking three arguments of the specified types, and returning int (10.1.7).
— end example ]
10
A single name can be used for several different functions in a single scope; this is function overloading (Clause
16). All declarations for a function shall have equivalent return types, parameter-type-lists, and requires-
clauses (17.6.6.1).
11
Functions shall not have a return type of type array or function, although they may have a return type of
type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays
of pointers to functions.
12
Types shall not be defined in return or parameter types. The type of a parameter or the return type for a
function definition shall not be an incomplete (possibly cv-qualified) class type in the context of the function
definition unless the function is deleted (11.4.3).
13
A typedef of function type may be used to declare a function but shall not be used to define a function (11.4).
[ Example:
typedef void F();
F fv;
// OK: equivalent to void fv();
F fv { }
// ill-formed
void fv() { }
// OK: definition of fv
— end example ]
14
An identifier can optionally be provided as a parameter name; if present in a function definition (11.4), it
names a parameter. [ Note: In particular, parameter names are also optional in function definitions and
names used for a parameter in different declarations and the definition of a function need not be the same. If
§ 11.3.5
188
a parameter name is present in a function declaration that is not a definition, it cannot be used outside of its
function declarator because that is the extent of its potential scope (6.3.4).
— end note ]
15
[ Example: The declaration
int i,
*pi,
f(),
*fpi(int),
(*pif)(const char*, const char*),
(*fpif(int))(int);
declares an integer i, a pointer pi to an integer, a function f taking no arguments and returning an integer,
a function fpi taking an integer argument and returning a pointer to an integer, a pointer pif to a function
which takes two pointers to constant characters and returns an integer, a function fpif taking an integer
argument and returning a pointer to a function that takes an integer argument and returns an integer. It is
especially useful to compare fpi and pif. The binding of *fpi(int) is *(fpi(int)), so the declaration
suggests, and the same construction in an expression requires, the calling of a function fpi, and then using
indirection through the (pointer) result to yield an integer. In the declarator (*pif)(const char*, const
char*), the extra parentheses are necessary to indicate that indirection through a pointer to a function yields
a function, which is then called.
— end example ] [ Note: Typedefs and trailing-return-types are sometimes
convenient when the return type of a function is complex. For example, the function fpif above could have
been declared
typedef int IFUNC(int);
IFUNC* fpif(int);
or
auto fpif(int)->int(*)(int);
A trailing-return-type is most useful for a type that would be more complicated to specify before the
declarator-id:
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
rather than
template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
— end note ]
16
A non-template function is a function that is not a function template specialization.
[Note: A function
template is not a function.
— end note ]
17
A declarator-id or abstract-declarator containing an ellipsis shall only be used in a parameter-declaration.
Such a parameter-declaration is a parameter pack (17.6.3). When it is part of a parameter-declaration-clause,
the parameter pack is a function parameter pack (17.6.3). [Note: Otherwise, the parameter-declaration is
part of a template-parameter-list and the parameter pack is a template parameter pack; see 17.1.
— end
note ] A function parameter pack is a pack expansion (17.6.3). [ Example:
template<typename... T> void f(T (* ...t)(int, int));
int add(int, int);
float subtract(int, int);
void g() {
f(add, subtract);
}
— end example ]
18
There is a syntactic ambiguity when an ellipsis occurs at the end of a parameter-declaration-clause without
a preceding comma. In this case, the ellipsis is parsed as part of the abstract-declarator if the type of the
parameter either names a template parameter pack that has not been expanded or contains auto; otherwise,
it is parsed as part of the parameter-declaration-clause.103
103) One can explicitly disambiguate the parse either by introducing a comma (so the ellipsis will be parsed as part of
the parameter-declaration-clause) or by introducing a name for the parameter (so the ellipsis will be parsed as part of the
declarator-id).
§ 11.3.5
189
11.3.6
Default arguments
[dcl.fct.default]
1
If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default
argument. Default arguments will be used in calls where trailing arguments are missing.
2
[ Example: The declaration
void point(int = 3, int = 4);
declares a function that can be called with zero, one, or two arguments of type int. It can be called in any
of these ways:
point(1,2); point(1); point();
The last two calls are equivalent to point(1,4) and point(3,4), respectively.
— end example ]
3
A default argument shall be specified only in the parameter-declaration-clause of a function declaration or
lambda-declarator or in a template-parameter (17.1); in the latter case, the initializer-clause shall be an
assignment-expression. A default argument shall not be specified for a parameter pack. If it is specified in a
parameter-declaration-clause, it shall not occur within a declarator or abstract-declarator of a parameter-
declaration.104
4
For non-template functions, default arguments can be added in later declarations of a function in the
same scope. Declarations in different scopes have completely distinct sets of default arguments. That is,
declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice
versa. In a given function declaration, each parameter subsequent to a parameter with a default argument
shall have a default argument supplied in this or a previous declaration or shall be a function parameter pack.
A default argument shall not be redefined by a later declaration (not even to the same value). [ Example:
void g(int = 0, ...);
// OK, ellipsis is not a parameter so it can follow
// a parameter with a default argument
void f(int, int);
void f(int, int = 7);
void h() {
f(3);
// OK, calls f(3, 7)
void f(int = 1, int);
// error: does not use default from surrounding scope
}
void m() {
void f(int, int);
// has no defaults
f(4);
// error: wrong number of arguments
void f(int, int = 5);
// OK
f(4);
// OK, calls f(4, 5);
void f(int, int = 5);
// error: cannot redefine, even to same value
}
void n() {
f(6);
// OK, calls f(6, 7)
}
— end example ] For a given inline function defined in different translation units, the accumulated sets of
default arguments at the end of the translation units shall be the same; see 6.2. If a friend declaration
specifies a default argument expression, that declaration shall be a definition and shall be the only declaration
of the function or function template in the translation unit.
5
The default argument has the same semantic constraints as the initializer in a declaration of a variable of the
parameter type, using the copy-initialization semantics (11.6). The names in the default argument are bound,
and the semantic constraints are checked, at the point where the default argument appears. Name lookup
and checking of semantic constraints for default arguments in function templates and in member functions of
class templates are performed as described in 17.8.1. [ Example: In the following code, g will be called with
the value f(2):
int a = 1;
int f(int);
int g(int x = f(a));
// default argument: f(::a)
void h() {
a = 2;
104) This means that default arguments cannot appear, for example, in declarations of pointers to functions, references to
functions, or typedef declarations.
§ 11.3.6
190
{
int a = 3;
g();
// g(f(::a))
}
}
— end example ]
[Note: In member function declarations, names in default arguments are looked up as
described in 6.4.1. Access checking applies to names in default arguments as described in Clause 14.
— end
note ]
6
Except for member functions of class templates, the default arguments in a member function definition that
appears outside of the class definition are added to the set of default arguments provided by the member
function declaration in the class definition; the program is ill-formed if a default constructor (15.1), copy
or move constructor, or copy or move assignment operator (15.8) is so declared. Default arguments for a
member function of a class template shall be specified on the initial declaration of the member function
within the class template. [ Example:
class C {
void f(int i = 3);
void g(int i, int j = 99);
};
void C::f(int i = 3) {}
// error: default argument already specified in class scope
void C::g(int i = 88, int j) {} // in this translation unit, C::g can be called with no argument
— end example ]
7
[ Note: A local variable cannot be odr-used (6.2) in a default argument.
— end note ] [ Example:
void f() {
int i;
extern void g(int x = i);
// error
extern void h(int x = sizeof(i)); // OK
// ...
}
— end example ]
8
[ Note: The keyword this may not appear in a default argument of a member function; see 8.4.2. [ Example:
class A {
void f(A* p = this) { }
// error
};
— end example ]
— end note ]
9
A default argument is evaluated each time the function is called with no argument for the corresponding
parameter. A parameter shall not appear as a potentially-evaluated expression in a default argument.
Parameters of a function declared before a default argument are in scope and can hide namespace and class
member names. [ Example:
int a;
int f(int a, int b = a);
// error: parameter a used as default argument
typedef int I;
int g(float I, int b = I(2));
// error: parameter I found
int h(int a, int b = sizeof(a));
// OK, unevaluated operand
— end example ] A non-static member shall not appear in a default argument unless it appears as the id-
expression of a class member access expression (8.5.1.5) or unless it is used to form a pointer to member (8.5.2.1).
[ Example: The declaration of X::mem1() in the following example is ill-formed because no object is supplied
for the non-static member X::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a);
// error: non-static member a used as default argument
int mem2(int i = b);
// OK; use X::b
static int b;
};
§ 11.3.6
191
The declaration of X::mem2() is meaningful, however, since no object is needed to access the static member
X::b. Classes, objects, and members are described in Clause 12.
— end example ] A default argument is not
part of the type of a function. [ Example:
int f(int = 0);
void h() {
int j = f(1);
int k = f();
// OK, means f(0)
}
int (*p1)(int) = &f;
int (*p2)() = &f;
// error: type mismatch
— end example ] When a declaration of a function is introduced by way of a using-declaration (10.3.3), any
default argument information associated with the declaration is made known as well. If the function is
redeclared thereafter in the namespace with additional default arguments, the additional arguments are also
known at any point following the redeclaration where the using-declaration is in scope.
10
A virtual function call (13.3) uses the default arguments in the declaration of the virtual function determined
by the static type of the pointer or reference denoting the object. An overriding function in a derived class
does not acquire default arguments from the function it overrides. [ Example:
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f();
// OK, calls pa->B::f(7)
pb->f();
// error: wrong number of arguments for B::f()
}
— end example ]
11.4
Function definitions
[dcl.fct.def]
11.4.1
In general
[dcl.fct.def.general]
1
Function definitions have the form
function-definition:
attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
attribute-specifier-seqopt decl-specifier-seqopt declarator requires-clause function-body
function-body:
ctor-initializeropt compound-statement
function-try-block
= default ;
= delete ;
Any informal reference to the body of a function should be interpreted as a reference to the non-terminal
function-body. The optional attribute-specifier-seq in a function-definition appertains to the function. A
virt-specifier-seq can be part of a function-definition only if it is a member-declaration (12.2).
2
In a function-definition, either void declarator ; or declarator ; shall be a well-formed function declaration
as described in 11.3.5. A function shall be defined only in namespace or class scope.
3
[ Example: A simple example of a complete function definition is
int max(int a, int b, int c) {
int m = (a > b) ? a : b;
return (m > c) ? m : c;
}
Here int is the decl-specifier-seq; max(int a, int b, int c) is the declarator; { /* ... */ } is the
function-body.
— end example ]
§ 11.4.1
192
4
A ctor-initializer is used only in a constructor; see 15.1 and 15.6.
5
[ Note: A cv-qualifier-seq affects the type of this in the body of a member function; see 11.3.2.
— end note ]
6
[ Note: Unused parameters need not be named. For example,
void print(int a, int) {
std::printf("a = %d\n",a);
}
— end note ]
7
In the function-body, a function-local predefined variable denotes a block-scope object of static storage duration
that is implicitly defined (see 6.3.3).
8
The function-local predefined variable __func__ is defined as if a definition of the form
static const char __func__[] = "function-name ";
had been provided, where function-name is an implementation-defined string. It is unspecified whether
such a variable has an address distinct from that of any other object in the program.105 [ Example:
struct S {
S() : s(__func__) { }
// OK
const char* s;
};
void f(const char* s = __func__);
// error: __func__ is undeclared
— end example ]
11.4.2
Explicitly-defaulted functions
[dcl.fct.def.default]
1
A function definition whose function-body is of the form = default ; is called an explicitly-defaulted definition.
A function that is explicitly defaulted shall
(1.1)
be a special member function or a comparison operator (8.5.8, 8.5.9, 8.5.10), and
(1.2)
not have default arguments.
2
The type T1 of an explicitly defaulted function F is allowed to differ from the type T2 it would have had if it
were implicitly declared, as follows:
(2.1)
T1 and T2 may have differing ref-qualifiers; and
(2.2)
if T2 has a parameter of type const C&, the corresponding parameter of T1 may be of type C&.
If T1 differs from T2 in any other way, then:
(2.3)
if F is an assignment operator, and the return type of T1 differs from the return type of T2 or T1’s
parameter type is not a reference, the program is ill-formed;
(2.4)
otherwise, if F is explicitly defaulted on its first declaration, it is defined as deleted;
(2.5)
otherwise, the program is ill-formed.
3
An explicitly-defaulted function that is not defined as deleted may be declared constexpr only if it would
have been implicitly declared as constexpr. If a function is explicitly defaulted on its first declaration, it is
implicitly considered to be constexpr if the implicit declaration would be.
4
[ Example:
struct S {
constexpr S() = default;
// ill-formed: implicit S() is not constexpr
S(int a = 0) = default;
// ill-formed: default argument
void operator=(const S&) = default;
// ill-formed: non-matching return type
~S() noexcept(false) = default;
// deleted: exception specification does not match
private:
int i;
S(S&);
// OK: private copy constructor
};
S::S(S&) = default;
// OK: defines copy constructor
— end example ]
105) Implementations are permitted to provide additional predefined variables with names that are reserved to the implementation
(5.10). If a predefined variable is not odr-used (6.2), its string value need not be present in the program image.
§ 11.4.2
193
5
Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and
the implementation shall provide implicit definitions for them (15.1 15.4, 15.8), which might mean defining
them as deleted. A function is user-provided if it is user-declared and not explicitly defaulted or deleted
on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first
declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as
deleted, the program is ill-formed. [Note: Declaring a function as defaulted after its first declaration can
provide efficient execution and concise definition while enabling a stable binary interface to an evolving code
base. — end note ]
6
[ Example:
struct trivial {
trivial() = default;
trivial(const trivial&) = default;
trivial(trivial&&) = default;
trivial& operator=(const trivial&) = default;
trivial& operator=(trivial&&) = default;
~trivial() = default;
};
struct nontrivial1 {
nontrivial1();
};
nontrivial1::nontrivial1() = default;
// not first declaration
— end example ]
11.4.3
Deleted definitions
[dcl.fct.def.delete]
1
A function definition whose function-body is of the form = delete ; is called a deleted definition. A function
with a deleted definition is also called a deleted function.
2
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
[ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member
to the function. It applies even for references in expressions that are not potentially-evaluated. If a function
is overloaded, it is referenced only if the function is selected by overload resolution. The implicit odr-use (6.2)
of a virtual function does not, by itself, constitute a reference.
— end note ]
3
[ Example: One can enforce non-default-initialization and non-integral initialization with
struct onlydouble {
onlydouble() = delete;
// OK, but redundant
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
— end example ]
[Example: One can prevent use of a class in certain new-expressions by using deleted definitions of a
user-declared operator new for that class.
struct sometype {
void* operator new(std::size_t) = delete;
void* operator new[](std::size_t) = delete;
};
sometype* p = new sometype;
// error, deleted class operator new
sometype* q = new sometype[3];
// error, deleted class operator new[]
— end example ]
[Example: One can make a class uncopyable, i.e., move-only, by using deleted definitions of the copy
constructor and copy assignment operator, and then providing defaulted definitions of the move constructor
and move assignment operator.
struct moveonly {
moveonly() = default;
moveonly(const moveonly&) = delete;
moveonly(moveonly&&) = default;
moveonly& operator=(const moveonly&) = delete;
moveonly& operator=(moveonly&&) = default;
§ 11.4.3
194
~moveonly() = default;
};
moveonly* p;
moveonly q(*p);
// error, deleted copy constructor
— end example ]
4
A deleted function is implicitly an inline function (10.1.6). [ Note: The one-definition rule (6.2) applies to
deleted definitions.
— end note ] A deleted definition of a function shall be the first declaration of the
function or, for an explicit specialization of a function template, the first declaration of that specialization. An
implicitly declared allocation or deallocation function (6.6.4.4) shall not be defined as deleted. [ Example:
struct sometype {
sometype();
};
sometype::sometype() = delete;
// ill-formed; not first declaration
— end example ]
11.5
Structured binding declarations
[dcl.struct.bind]
1
A structured binding declaration introduces the identifier s v0, v1, v2, ... of the identifier-list as names (6.3.1),
called structured bindings. Let cv denote the cv-qualifiers in the decl-specifier-seq. First, a variable with
a unique name e is introduced. If the assignment-expression in the initializer has array type A and no
ref-qualifier is present, e has type cv A and each element is copy-initialized or direct-initialized from the
corresponding element of the assignment-expression as specified by the form of the initializer. Otherwise, e
is defined as-if by
attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt e initializer ;
where the declaration is never interpreted as a function declaration and the parts of the declaration other
than the declarator-id are taken from the corresponding structured binding declaration. The type of the
id-expression e is called E. [ Note: E is never a reference type (8.2).
— end note ]
2
If E is an array type with element type T, the number of elements in the identifier-list shall be equal to
the number of elements of E. Each vi is the name of an lvalue that refers to the element i of the array
and whose type is T; the referenced type is T. [Note: The top-level cv-qualifiers of T are cv.
— end note ]
[ Example:
auto f() -> int(&)[2];
auto [ x, y ] = f();
// x and y refer to elements in a copy of the array return value
auto& [ xr, yr ] = f();
// xr and yr refer to elements in the array referred to by f’s return value
— end example ]
3
Otherwise, if the qualified-id std::tuple_size<E> names a complete type, the expression std::tuple_-
size<E>::value shall be a well-formed integral constant expression and the number of elements in the
identifier-list shall be equal to the value of that expression. The unqualified-id get is looked up in the scope of
E by class member access lookup (6.4.5), and if that finds at least one declaration, the initializer is e.get<i>().
Otherwise, the initializer is get<i>(e), where get is looked up in the associated namespaces (6.4.2). In either
case, get<i> is interpreted as a template-id. [Note: Ordinary unqualified lookup (6.4.1) is not performed.
— end note ] In either case, e is an lvalue if the type of the entity e is an lvalue reference and an xvalue
otherwise. Given the type Ti designated by std::tuple_element<i, E>::type, variables are introduced
with unique names ri of type “reference to Ti” initialized with the initializer (11.6.3), where the reference is
an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise. Each vi is the name of an
lvalue of type Ti that refers to the object bound to ri; the referenced type is Ti.
4
Otherwise, all of E’s non-static data members shall be public direct members of E or of the same unambiguous
public base class of E, E shall not have an anonymous union member, and the number of elements in the
identifier-list shall be equal to the number of non-static data members of E. Designating the non-static data
members of E as m0, m1, m2, ... (in declaration order), each vi is the name of an lvalue that refers to the
member mi of e and whose type is cv Ti, where Ti is the declared type of that member; the referenced type is
cv Ti. The lvalue is a bit-field if that member is a bit-field. [ Example:
struct S { int x1 : 2; volatile double y1; };
S f();
const auto [ x, y ] = f();
§ 11.5
195
The type of the id-expression x is “const int”, the type of the id-expression y is “const volatile double”.
— end example ]
11.6
Initializers
[dcl.init]
1
The process of initialization described in this subclause applies to all initializations regardless of syntactic
context, including the initialization of a function parameter (8.5.1.2), the initialization of a return value (9.6.3),
or when an initializer follows a declarator.
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
braced-init-list:
{ initializer-list ,opt }
{ designated-initializer-list ,opt }
{ }
initializer-list:
initializer-clause ...opt
initializer-list , initializer-clause ...opt
designated-initializer-list:
designated-initializer-clause
designated-initializer-list , designated-initializer-clause
designated-initializer-clause:
designator brace-or-equal-initializer
designator:
. identifier
expr-or-braced-init-list:
expression
braced-init-list
[ Note: The rules in this subclause apply even if the grammar permits only the brace-or-equal-initializer form
of initializer in a given context.
— end note ]
2
Except for objects declared with the constexpr specifier, for which see 10.1.5, an initializer in the definition
of a variable can consist of arbitrary expressions involving literals and previously declared variables and
functions, regardless of the variable’s storage duration. [ Example:
int f(int);
int a = 2;
int b = f(a);
int c(b);
— end example ]
3
[ Note: Default arguments are more restricted; see 11.3.6.
— end note ]
4
[Note: The order of initialization of variables with static storage duration is described in 6.8.3 and 9.7.
— end note ]
5
A declaration of a block-scope variable with external or internal linkage that has an initializer is ill-formed.
6
To zero-initialize an object or reference of type T means:
(6.1)
if T is a scalar type (6.7), the object is initialized to the value obtained by converting the integer literal
0
(zero) to T;106
(6.2)
if T is a (possibly cv-qualified) non-union class type, its padding bits (6.7) are initialized to zero bits
and each non-static data member, each non-virtual base class subobject, and, if the object is not a base
class subobject, each virtual base class subobject is zero-initialized;
106) As specified in 7.11, converting an integer literal whose value is 0 to a pointer type results in a null pointer value.
§ 11.6
196
(6.3)
if T is a (possibly cv-qualified) union type, its padding bits (6.7) are initialized to zero bits and the
object’s first non-static named data member is zero-initialized;
(6.4)
if T is an array type, each element is zero-initialized;
(6.5)
if T is a reference type, no initialization is performed.
7
To default-initialize an object of type T means:
(7.1)
If T is a (possibly cv-qualified) class type (Clause 12), constructors are considered. The applicable
constructors are enumerated (16.3.1.3), and the best one for the initializer () is chosen through overload
resolution (16.3). The constructor thus selected is called, with an empty argument list, to initialize the
object.
(7.2)
If T is an array type, each element is default-initialized.
(7.3)
Otherwise, no initialization is performed.
A class type T is const-default-constructible if default-initialization of T would invoke a user-provided
constructor of T (not inherited from a base class) or if
(7.4)
each direct non-variant non-static data member M of T has a default member initializer or, if M is of
class type X (or array thereof), X is const-default-constructible,
(7.5)
if T is a union with at least one non-static data member, exactly one variant member has a default
member initializer,
(7.6)
if T is not a union, for each anonymous union member with at least one non-static data member (if
any), exactly one non-static data member has a default member initializer, and
(7.7)
each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a const-qualified type T, T shall be a const-
default-constructible class type or array thereof.
8
To value-initialize an object of type T means:
(8.1)
if T is a (possibly cv-qualified) class type (Clause 12) with either no default constructor (15.1) or a
default constructor that is user-provided or deleted, then the object is default-initialized;
(8.2)
if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then
the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T
has a non-trivial default constructor, the object is default-initialized;
(8.3)
if T is an array type, then each element is value-initialized;
(8.4)
otherwise, the object is zero-initialized.
9
A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed.
10
[Note: Every object of static storage duration is zero-initialized at program startup before any other
initialization takes place. In some cases, additional initialization is done later.
— end note ]
11
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
[ Note: Since () is not permitted by the syntax for initializer,
X a();
is not the declaration of an object of class X, but the declaration of a function taking no argument and
returning an X. The form () is permitted in certain other initialization contexts (8.5.2.4, 8.5.1.3, 15.6.2).
— end note ]
12
If no initializer is specified for an object, the object is default-initialized. When storage for an object
with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if
no initialization is performed for the object, that object retains an indeterminate value until that value
is replaced (8.5.18). [ Note: Objects with static or thread storage duration are zero-initialized, see 6.8.3.2.
— end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the
following cases:
(12.1)
If an indeterminate value of unsigned narrow character type (6.7.1) or std::byte type (21.2.1) is
produced by the evaluation of:
(12.1.1)
the second or third operand of a conditional expression (8.5.16),
(12.1.2)
the right operand of a comma expression (8.5.19),
§ 11.6
197
(12.1.3)
the operand of a cast or conversion (7.8, 8.5.1.3, 8.5.1.9, 8.5.3) to an unsigned narrow character
type or std::byte type (21.2.1), or
(12.1.4)
a discarded-value expression (8.2),
then the result of the operation is an indeterminate value.
(12.2)
If an indeterminate value of unsigned narrow character type or std::byte type is produced by the
evaluation of the right operand of a simple assignment operator (8.5.18) whose first operand is an lvalue
of unsigned narrow character type or std::byte type, an indeterminate value replaces the value of the
object referred to by the left operand.
(12.3)
If an indeterminate value of unsigned narrow character type is produced by the evaluation of the
initialization expression when initializing an object of unsigned narrow character type, that object is
initialized to an indeterminate value.
(12.4)
If an indeterminate value of unsigned narrow character type or std::byte type is produced by the
evaluation of the initialization expression when initializing an object of std::byte type, that object is
initialized to an indeterminate value.
[ Example:
int f(bool b) {
unsigned char c;
unsigned char d = c;
// OK, d has an indeterminate value
int e = d;
// undefined behavior
return b ? d : 0;
// undefined behavior if b is true
}
— end example ]
13
An initializer for a static member is in the scope of the member’s class. [ Example:
int a;
struct X {
static int a;
static int b;
};
int X::a = 1;
int X::b = a;
// X::b = X::a
— end example ]
14
If the entity being initialized does not have class type, the expression-list in a parenthesized initializer shall
be a single expression.
15
The initialization that occurs in the = form of a brace-or-equal-initializer or condition (9.4), as well as
in argument passing, function return, throwing an exception (18.1), handling an exception (18.3), and
aggregate member initialization (11.6.1), is called copy-initialization. [ Note: Copy-initialization may invoke a
move (15.8).
— end note ]
16
The initialization that occurs in the forms
T x(a);
T x{a};
as well as in new expressions (8.5.2.4), static_cast expressions (8.5.1.9), functional notation type conversions
(8.5.1.3), mem-initializer s (15.6.2), and the braced-init-list form of a condition is called direct-initialization.
17
The semantics of initializers are as follows. The destination type is the type of the object or reference being
initialized and the source type is the type of the initializer expression. If the initializer is not a single (possibly
parenthesized) expression, the source type is not defined.
(17.1)
If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is
list-initialized (11.6.4).
(17.2)
If the destination type is a reference type, see 11.6.3.
(17.3)
If the destination type is an array of characters, an array of char16_t, an array of char32_t, or an
array of wchar_t, and the initializer is a string literal, see 11.6.2.
§ 11.6
198
(17.4)
If the initializer is (), the object is value-initialized.
(17.5)
Otherwise, if the destination type is an array, the program is ill-formed.
(17.6)
If the destination type is a (possibly cv-qualified) class type:
(17.6.1)
If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same
class as the class of the destination, the initializer expression is used to initialize the destination
object.
[Example: T x = T(T(T())); calls the T default constructor to initialize x.
— end
example ]
(17.6.2)
Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the
cv-unqualified version of the source type is the same class as, or a derived class of, the class of the
destination, constructors are considered. The applicable constructors are enumerated (16.3.1.3),
and the best one is chosen through overload resolution (16.3). The constructor so selected is called
to initialize the object, with the initializer expression or expression-list as its argument(s). If no
constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
(17.6.3)
Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that
can convert from the source type to the destination type or (when a conversion function is used) to
a derived class thereof are enumerated as described in 16.3.1.4, and the best one is chosen through
overload resolution (16.3). If the conversion cannot be done or is ambiguous, the initialization is
ill-formed. The function selected is called with the initializer expression as its argument; if the
function is a constructor, the call is a prvalue of the cv-unqualified version of the destination type
whose result object is initialized by the constructor. The call is used to direct-initialize, according
to the rules above, the object that is the destination of the copy-initialization.
(17.7)
Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered.
The applicable conversion functions are enumerated (16.3.1.5), and the best one is chosen through
overload resolution (16.3). The user-defined conversion so selected is called to convert the initializer
expression into the object being initialized. If the conversion cannot be done or is ambiguous, the
initialization is ill-formed.
(17.8)
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the
initializer expression. Standard conversions (Clause 7) will be used, if necessary, to convert the
initializer expression to the cv-unqualified version of the destination type; no user-defined conversions
are considered. If the conversion cannot be done, the initialization is ill-formed. When initializing a bit-
field with a value that it cannot represent, the resulting value of the bit-field is implementation-defined.
[Note: An expression of type “cv1 T” can initialize an object of type “cv2 T” independently of the
cv-qualifiers cv1 and cv2.
int a;
const int b = a;
int c = b;
— end note ]
18
An initializer-clause followed by an ellipsis is a pack expansion (17.6.3).
19
If the initializer is a parenthesized expression-list, the expressions are evaluated in the order specified for
function calls (8.5.1.2).
20
The same identifier shall not appear in multiple designator s of a designated-initializer-list.
21
An object whose initialization has completed is deemed to be constructed, even if no constructor of the
object’s class is invoked for the initialization. [Note: Such an object might have been value-initialized or
initialized by aggregate initialization (11.6.1) or by an inherited constructor (15.6.3).
— end note ]
22
A declaration that specifies the initialization of a variable, whether from an explicit initializer or by default-
initialization, is called the initializing declaration of that variable. [ Note: In most cases this is the defining
declaration (6.1) of the variable, but the initializing declaration of a non-inline static data member (12.2.3.2)
might be the declaration within the class definition and not the definition at namespace scope.
— end note ]
11.6.1
Aggregates
[dcl.init.aggr]
1
An aggregate is an array or a class (Clause 12) with
(1.1)
no user-provided, explicit, or inherited constructors (15.1),
(1.2)
no private or protected non-static data members (Clause 14),
§ 11.6.1
199
(1.3)
no virtual functions (13.3), and
(1.4)
no virtual, private, or protected base classes (13.1).
[Note: Aggregate initialization does not allow accessing protected and private base class’ members or
constructors.
— end note ]
2
The elements of an aggregate are:
(2.1)
for an array, the array elements in increasing subscript order, or
(2.2)
for a class, the direct base classes in declaration order, followed by the direct non-static data members
(12.2) that are not members of an anonymous union, in declaration order.
3
When an aggregate is initialized by an initializer list as specified in 11.6.4, the elements of the initializer list
are taken as initializers for the elements of the aggregate. The explicitly initialized elements of the aggregate
are determined as follows:
(3.1)
If the initializer list is a designated-initializer-list, the aggregate shall be of class type, the identifier in
each designator shall name a direct non-static data member of the class, and the explicitly initialized
elements of the aggregate are the elements that are, or contain, those members.
(3.2)
If the initializer list is an initializer-list, the explicitly initialized elements of the aggregate are the first
n elements of the aggregate, where n is the number of elements in the initializer list.
(3.3)
Otherwise, the initializer list must be {}, and there are no explicitly initialized elements.
4
For each explicitly initialized element:
(4.1)
If the element is an anonymous union object and the initializer list is a designated-initializer-list,
the anonymous union object is initialized by the designated-initializer-list { D
}, where D is the
designated-initializer-clause naming a member of the anonymous union object. There shall be only one
such designated-initializer-clause.
(4.2)
Otherwise, the element is copy-initialized from the corresponding initializer-clause or the brace-or-
equal-initializer of the corresponding designated-initializer-clause. If that initializer is of the form
assignment-expression or = assignment-expression and a narrowing conversion (11.6.4) is required to
convert the expression, the program is ill-formed. [ Note: If an initializer is itself an initializer list, the
element is list-initialized, which will result in a recursive application of the rules in this subclause if the
element is an aggregate.
— end note ]
[ Example:
struct A {
int x;
struct B {
int i;
int j;
} b;
} a = { 1, { 2, 3 } };
initializes a.x with 1, a.b.i with 2, a.b.j with 3.
struct base1 { int b1, b2 = 42; };
struct base2 {
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2 {
int d;
};
derived d1{{1, 2}, {}, 4};
derived d2{{}, {}, 4};
initializes d1.b1 with 1, d1.b2 with 2, d1.b3 with 42, d1.d with 4, and d2.b1 with 0, d2.b2 with
42, d2.b3
with 42, d2.d with 4.
— end example ]
5
For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
§ 11.6.1
200
(5.1)
If the element has a default member initializer (12.2), the element is initialized from that initializer.
(5.2)
Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer
list (11.6.4).
(5.3)
Otherwise, the program is ill-formed.
If the aggregate is a union and the initializer list is empty, then
(5.4)
if any variant member has a default member initializer, that member is initialized from its default
member initializer;
(5.5)
otherwise, the first member of the union (if any) is copy-initialized from an empty initializer list.
[ Example:
struct S { int a; const char* b; int c; int d = b[a]; };
S ss = { 1, "asdf" };
initializes ss.a with 1, ss.b with "asdf", ss.c with the value of an expression of the form int{} (that is,
0), and ss.d with the value of ss.b[ss.a] (that is, ’s’), and in
struct X { int i, j, k = 42; };
X a[] = { 1, 2, 3, 4, 5, 6 };
X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
a and b have the same value
struct A {
string a;
int b = 42;
int c = -1;
};
A{.c=21} has the following steps:
(5.6)
Initialize a with {}
(5.7)
Initialize b with = 42
(5.8)
Initialize c with = 21
— end example ]
6
The initializations of the elements of the aggregate are evaluated in the element order. That is, all value
computations and side effects associated with a given element are sequenced before those of any element that
follows it in order.
7
An aggregate that is a class can also be initialized with a single expression not enclosed in braces, as described
in 11.6.
8
An array of unknown bound initialized with a brace-enclosed initializer-list containing n initializer-clauses,
where n shall be greater than zero, is defined as having n elements (11.3.4). [ Example:
int x[] = { 1, 3, 5 };
declares and initializes x as a one-dimensional array that has three elements since no size was specified
and there are three initializers.
— end example ] An empty initializer list {} shall not be used as the
initializer-clause for an array of unknown bound.107 [ Note: A default member initializer does not determine
the bound for a member array of unknown bound. Since the default member initializer is ignored if a suitable
mem-initializer is present (15.6.2), the default member initializer is not considered to initialize the array of
unknown bound. [ Example:
struct S {
int y[] = { 0 };
// error: non-static data member of incomplete type
};
— end example ]
— end note ]
9
[ Note: Static data members, non-static data members of anonymous union members, and unnamed bit-fields
are not considered elements of the aggregate. [ Example:
struct A {
int i;
107) The syntax provides for empty initializer-lists, but nonetheless C++ does not have zero length arrays.
§ 11.6.1
201

 

 

 

 

 

 

 

Content      ..     5      6      7      8     ..