______________________________________________________________________
8 Declarators [dcl.decl]
______________________________________________________________________
1 A declarator declares a single object, 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
2 The two components of a declaration are the specifiers (decl-
specifier-seq; _dcl.spec_) and the declarators (init-declarator-list).
The specifiers indicate the type, storage class or other properties of
the objects, functions or typedefs being declared. The declarators
specify the names of these objects, functions or typedefs, 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 _dcl.init_
and _class.init_.
3 Each init-declarator in a declaration is analyzed separately as if it
was in a declaration by itself.1)
_________________________
1) 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 equvalent to
T D1; T D2; ... T Dn;
where T is a decl-specifier-seq and each Di is a init-declarator. The
exception occurs when a name introduced by one of the declarators
hides a type name used by the dcl-specifiers, so that when the same
dcl-specifiers 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
4 Declarators have the syntax
declarator:
direct-declarator
ptr-operator declarator
direct-declarator:
declarator-id
direct-declarator ( parameter-declaration-clause ) cv-qualifier-seqopt exception-specificationopt
direct-declarator [ constant-expressionopt ]
( declarator )
ptr-operator:
* cv-qualifier-seqopt
&
::opt nested-name-specifier * cv-qualifier-seqopt
cv-qualifier-seq:
cv-qualifier cv-qualifier-seqopt
cv-qualifier:
const
volatile
declarator-id:
::opt id-expression
::opt nested-name-specifieropt type-name
A class-name has special meaning in a declaration of the class of that
name and when qualified by that name using the scope resolution opera
tor :: (_expr.prim_, _class.ctor_, _class.dtor_).
8.1 Type names [dcl.name]
1 To specify type conversions explicitly, and as an argument of sizeof,
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 an
object or function of that type that omits the name of the object or
function.
type-id:
type-specifier-seq abstract-declaratoropt
type-specifier-seq:
type-specifier type-specifier-seqopt
abstract-declarator:
ptr-operator abstract-declaratoropt
direct-abstract-declarator
direct-abstract-declarator:
direct-abstract-declaratoropt ( parameter-declaration-clause ) cv-qualifier-seqopt exception-specificationopt
direct-abstract-declaratoropt [ constant-expressionopt ]
( abstract-declarator )
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 param
eters) returning pointer to int," and "pointer to a function of dou
ble) returning int.'' ]
2 A type can also be named (often more easily) by using a typedef
(_dcl.typedef_).
8.2 Ambiguity resolution [dcl.ambig.res]
1 The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in _stmt.ambig_ 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
_stmt.ambig_, the resolution is to consider any construct that could
possibly be a declaration a declaration. [Note: a declaration can be
explicitly disambiguated by a nonfunction-style cast, by a = to indi
cate initialization or by removing the redundant parentheses around
the parameter name. ] [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 z = int(a); // object declaration
}
--end example]
2 The ambiguity arising from the similarity between a function-style
cast and a type-id can occur in different contexts. The ambiguity
appears as a choice between a function-style cast expression and a
declaration of a type. The resolution is that any construct that
could possibly be a type-id in its syntactic context shall be consid
ered a type-id.
3 [Example:
#include <cstddef>
char *p;
void *operator new(size_t, int);
void foo() {
const int x = 63;
new (int(*p)) int; // new-placement expression
new (int(*[x])); // new type-id
}
4 For another example,
template <class T>
struct S {
T *p;
};
S<int()> x; // type-id
S<int(1)> y; // expression (ill-formed)
5 For another example,
void foo()
{
sizeof(int(1)); // expression
sizeof(int()); // type-id (ill-formed)
}
6 For another example,
void foo()
{
(int(1)); // expression
(int())1; // type-id (ill-formed)
}
--end example]
7 Another ambiguity arises in a parameter-declaration-clause of a func
tion declaration, or in a type-id that is the operand of a sizeof or
typeid operator, 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 ptr
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]
8.3 Meaning of declarators [dcl.meaning]
1 A list of declarators appears after an optional (_dcl.dcl_) decl-
specifier-seq (_dcl.spec_). Each declarator contains exactly one
declarator-id; it names the identifier that is declared. The id-
expression of a declarator-id shall be a simple identifier except for
the declaration of some special functions (_class.conv_, _class.dtor_,
_over.oper_) and for the declaration of template specializations or
partial specializations (_temp.spec_). A declarator-id shall not be
qualified except for the definition of a member function
(_class.mfct_) or static data member (_class.static_) or nested class
(_class.nest_) outside of its class, the definition or explicit
instantiation of a function, variable or class member of a namespace
outside of its namespace, or the definition of a previously declared
explicit specialization outside of its namespace, or the declaration
of a friend function that is a member of another class or namespace
(_class.friend_). When the declarator-id is qualified, the declara
tion shall refer to a previously declared member of the class or
namespace to which the qualifier refers. [Note: if the qualifier is
the global :: scope resolution operator, the declarator-id refers to a
name declared in the global namespace scope. ] In the qualified
declarator-id for a class or namespace member definition that appears
outside of the member's class or namespace, the nested-name-specifier
shall not name any of the namespaces that enclose the member's defini
tion. [Example:
namespace A {
struct B {
void f();
};
void A::B::f() { } // ill-formed: the declarator must not be
// qualified with A::
}
--end example]
2 An auto, static, extern, register, mutable, friend, inline, virtual,
or typedef specifier applies directly to each declarator-id in a init-
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 a decl-specifier-seq and D is a declarator. The following
subclauses give a recursive procedure for determining the type speci
fied 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"
(_dcl.type.simple_). ]
5 In a declaration 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.
8.3.1 Pointers [dcl.ptr]
1 In a declaration T D where D has the form
* 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.
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; // okay, but would make p point to ci ...
// ... because of previous error
*p = 5; // clobber ci
--end example]
3 See also _expr.ass_ and _dcl.init_.
4 [Note: there are no pointers to references; see _dcl.ref_. Since the
address of a bit-field (_class.bit_) cannot be taken, a pointer can
never point to a bit-field. ]
8.3.2 References [dcl.ref]
1 In a declaration T D where D has the form
& 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." Cv-qualified refer
ences are ill-formed except when the cv-qualifiers are introduced
through the use of a typedef (_dcl.typedef_) or of a template type
argument (_temp.arg_), in which case the cv-qualifiers are ignored.
[Example: in
typedef int& A;
const A aref = 3; // ill-formed;
// non-const reference initialized with rvalue
the type of aref is "reference to int", not "const reference to int".
] [Note: a reference can be thought of as a name of an object. ] A
declarator that specifies the type "reference to cv void" is ill-
formed.
2 [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 _dcl.init.ref_. ]
3 It is unspecified whether or not a reference requires storage
(_basic.stc_).
4 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 (_dcl.init.ref_) except when the declaration
contains an explicit extern specifier (_dcl.stc_), is a class member
(_class.mem_) declaration within a class declaration, or is the decla
ration of a parameter or a return type (_dcl.fct_); see _basic.def_.
A reference shall be initialized to refer to a valid object or func
tion. [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 dereferencing a null
pointer, which causes undefined behavior. As described in
_class.bit_, a reference cannot be bound directly to a bit-field. ]
8.3.3 Pointers to members [dcl.mptr]
1 In a declaration T D where D has the form
::opt nested-name-specifier * cv-qualifier-seqopt D1
and the nested-name-specifier names a class, and the type of the iden
tifier 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."
2 [Example:
class X {
public:
void f(int);
int a;
};
class 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
(_class.static_), a member with reference type, or "cv void." [Note:
see also _expr.unary_ and _expr.mptr.oper_. The type "pointer to mem
ber" 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++. ]
8.3.4 Arrays [dcl.array]
1 In a declaration T D where D has the form
D1 [constant-expressionopt]
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. T is called the array element type; this type shall not
be a reference type, the type void, a function type or an abstract
class type. If the constant-expression (_expr.const_) is present, it
shall be an integral constant expression 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." If the constant expression is omitted, the type of the identi
fier 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 _basic.types_. Any 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."
An object of array type contains a contiguously allocated non-empty
set of N sub-objects of type T. [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]
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 multidimen
sional array is created; the constant expressions that specify the
bounds of the arrays can be omitted only for the first member of the
sequence. [Note: this elision is useful for function parameters of
array types, and when the array is external and the definition, which
allocates storage, is given elsewhere. ] The first constant-
expression can also be omitted when the declarator is followed by an
initializer (_dcl.init_). In this case the bound is calculated from
the number of initial elements (say, N) supplied (_dcl.init.aggr_),
and the type of the identifier of D is "array of N T."
4 [Example:
float fa[17], *afp[17];
declares an array of float numbers and an array of pointers to float
numbers. For another example,
static int x3d[3][5][7];
declares a static three-dimensional array of integers, with rank
3×5×7. In complete detail, x3d is an array of three items; each item
is an array of five arrays; each of the latter arrays is an array of
seven integers. Any of the expressions x3d, x3d[i], x3d[i][j],
x3d[i][j][k] can reasonably appear in an expression. ]
5 [Note: conversions affecting lvalues of array type are described in
_conv.array_. Objects of array types cannot be modified, see
_basic.lval_. ]
6 Except where it has been declared for a class (_over.sub_), the sub
script operator [] is interpreted in such a way that E1[E2] is identi
cal to *((E1)+(E2)). 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, sub
scripting is a commutative operation.
7 A consistent rule is followed for multidimensional arrays. If E is an
n-dimensional array of rank i×j×...×k, then E appearing in an expres
sion is converted to a pointer to an (n-1)-dimensional array with rank
j×...×k. If the * operator, either explicitly or implicitly as a
result of subscripting, is applied to this pointer, the result is the
pointed-to (n-1)-dimensional array, which itself is immediately con
verted into a pointer.
8 [Example: consider
int x[3][5];
Here x is a 3×5 array of integers. When x appears in an expression,
it is converted to a pointer to (the first of three) five-membered
arrays of integers. In the expression x[i], which is equivalent to
*(x+i), x is first converted to a pointer as described; then x+i is
converted to the type of x, which involves multiplying i by the length
of the object to which the pointer points, namely five integer
objects. The results are added and indirection applied to yield an
array (of five integers), which in turn is converted to a pointer to
the first of the integers. If there is another subscript the same
argument applies again; this time the result is an integer. ]
9 [Note: it follows from all this that arrays in C++ are stored row-wise
(last subscript varies fastest) and that the first subscript in the
declaration helps determine the amount of storage consumed by an array
but plays no other part in subscript calculations. ]
8.3.5 Functions [dcl.fct]
1 In a declaration T D where D has the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt exception-specificationopt
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 function of (parameter-declaration-
clause) cv-qualifier-seqopt returning T"; a type of this form is a
function type2).
parameter-declaration-clause:
parameter-declaration-listopt ...opt
parameter-declaration-list , ...
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
decl-specifier-seq declarator
decl-specifier-seq declarator = assignment-expression
decl-specifier-seq abstract-declaratoropt
decl-specifier-seq abstract-declaratoropt = assignment-expression
2 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 _expr.call_. ] If the parameter-
declaration-clause is empty, the function takes no arguments. The
parameter list (void) is equivalent to the empty parameter list.
Except for this special case, void shall not be a parameter type
(though types derived from void, such as void*, can). If the parame
ter-declaration-clause terminates with an ellipsis, the number of
arguments shall be equal to or greater than the number of parameters
specified. Where syntactically correct, ", ..." 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*. ] [Note: the standard header <cstdarg> contains a
mechanism for accessing arguments passed using the ellipsis (see
_expr.call_ and _lib.support.runtime_). ]
3 A single name can be used for several different functions in a single
scope; this is function overloading (_over_). All declarations for a
function with a given parameter list shall agree exactly both in the
type of the value returned and in the number and type of parameters;
the presence or absence of the ellipsis is considered part of the
function type. The type of a function is determined using the follow
ing rules. The type of each parameter 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 "function returning
T" is adjusted to be "pointer to T" or "pointer to function returning
T," respectively. After producing the list of parameter types, sev
eral transformations take place upon these types to determine the
function type. Any cv-qualifier modifying a parameter type is
deleted; e.g., the type void(const int) becomes void(int). Such cv-
qualifiers only affect the definition of the parameter within the body
_________________________
2) As indicated by the syntax, cv-qualifiers are a significant compo
nent in function return types.
of the function; they do not affect the function type. If a storage-
class-specifier modifies a parameter type, the specifier is deleted;
e.g., register char* becomes char*. Such storage-class-qualifiers
affect only the definition of the parameter within the body of the
function; they do not affect the function type. The resulting list of
transformed parameter types is the function's parameter type list. A
cv-qualifier-seq shall only be part of the function type for a non
static member function, the function type to which a pointer to member
refers, or the top-level function type of a function typedef declara
tion. 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,
i.e., it does not create a cv-qualified function type. In fact, if at
any time in the determination of a type a cv-qualified function type
is formed, the program is ill-formed. [Example:
typedef void F();
struct S {
const F f; // ill-formed:
// not equivalent to: void f() const;
};
--end example] The return type, the parameter type list and the cv-
qualifier-seq, but not the default arguments (_dcl.fct.default_) or
the exception specification (_except.spec_), are part of the function
type. [Note: function types are checked during the assignments and
initializations of pointer-to-functions, reference-to-functions, and
pointer-to-member-functions. ]
4 [Example: the declaration
int fseek(FILE*, long, int);
declares a function taking three arguments of the specified types, and
returning int (_dcl.type_). ]
5 If the type of a parameter includes a type of the form "pointer to
array of unknown bound of T" or "reference to array of unknown bound
of T," the program is ill-formed.3) 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.
Types shall not be defined in return or parameter types.
6 A typedef of function type may be used to declare a function but shall
not be used to define a function. [Example:
typedef void F();
F fv; // ok: equivalent to void fv();
F fv { } // ill-formed
void fv() { } // ok: definition of fv
--end example] A typedef of a function type whose declarator includes
_________________________
3) This excludes parameters of type "ptr-arr-seq T2" where T2 is
"pointer to array of unknown bound of T" and where ptr-arr-seq means
any sequence of "pointer to" and "array of" derived declarator types.
This exclusion applies to the parameters of the function, and if a pa
rameter is a pointer to function or pointer to member function then to
its parameters also, etc.
a cv-qualifier-seq shall be used only to declare the function type for
a nonstatic member function, to declare the function type to which a
pointer to member refers, or to declare the top-level function type of
another function typedef declaration. [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 An identifier can optionally be provided as a parameter name; if pre
sent in a function definition (_dcl.fct.def_), it names a parameter
(sometimes called "formal argument"). [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 a parameter name is present in a function
declaration that is not a definition, it cannot be used outside of the
parameter-declaration-clause since it goes out of scope at the end of
the function declarator (_basic.scope_). ]
8 [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 inte
ger 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. ]
[Note: typedefs 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);
--end note]
8.3.6 Default arguments [dcl.fct.default]
1 If an expression is specified in a parameter declaration this expres
sion 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 argu
ments 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. ]
3 A default argument expression shall be specified only in the parame
ter-declaration-clause of a function declaration or in a template-
parameter (_temp.param_). If it is specified in a parameter-
declaration-clause, it shall not occur within a declarator or
abstract-declarator of a parameter-declaration.4)
4 For non-template functions, default arguments can be added in later
declarations of a function in the same scope. Declarations in differ
ent 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, all parameters subsequent to a parameter with a default
argument shall have default arguments supplied in this or previous
declarations. A default argument shall not be redefined by a later
declaration (not even to the same value). [Example:
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 _basic.def.odr_.
_________________________
4) This means that default arguments cannot appear, for example, in
declarations of pointers to functions, references to functions, or
typedef declarations.
5 Default argument expressions have their names bound and their types
checked at the point of declaration. [Example: in the following code,
g will be called with the value f(1):
int a = 1;
int f(int);
int g(int x = f(a)); // default argument: f(::a)
void h() {
a = 2;
{
int a = 3;
g(); // g(f(::a))
}
}
--end example] [Note: in member function declarations, names in
default argument expressions are looked up as described in
_basic.lookup.unqual_. Access checking applies to names in default
argument expressions as described in _class.access_. ]
6 The default arguments in a member function definition that appears
outside of the class definition are added to the set of default argu
ments provided by the member function declaration in the class defini
tion. [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 Local variables shall not be used in default argument expressions.
[Example:
void f()
{
int i;
extern void g(int x = i); // error
// ...
}
--end example]
8 The keyword this shall not be used in a default argument of a member
function. [Example:
class A {
void f(A* p = this) { } // error
};
--end example]
9 Default arguments are evaluated at each point of call before entry
into a function. The order of evaluation of function arguments is
unspecified. Consequently, parameters of a function shall not be used
in default argument expressions, even if they are not evaluated.
Parameters of a function declared before a default argument expression
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)); // error, parameter `a' used
// in default argument
--end example] Similarly, a nonstatic member shall not be used in a
default argument expression, even if it is not evaluated, unless it
appears as the id-expression of a class member access expression
(_expr.ref_) or unless it is used to form a pointer to member
(_expr.unary.op_). [Example: the declaration of X::mem1() in the fol
lowing example is ill-formed because no object is supplied for the
nonstatic member X::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a); // error: nonstatic member `a'
// used as default argument
int mem2(int i = b); // ok; use X::b
static b;
};
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 _class_. ] 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(); // fine, 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 (_namespace.udecl_), any default argument
information associated with the declaration is imported as well.
+------- BEGIN BOX 1 -------+
Can additional default arguments be added to the function thereafter
by way of redeclarations of the function? Can the function be rede
clared in the namespace with added default arguments, and if so, are
those added arguments visible to those who have imported the function
via using?
+------- END BOX 1 -------+
10A virtual function call (_class.virtual_) 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]
8.4 Function definitions [dcl.fct.def]
1 Function definitions have the form
function-definition:
decl-specifier-seqopt declarator ctor-initializeropt function-body
decl-specifier-seqopt declarator function-try-block
function-body:
compound-statement
The declarator in a function-definition shall have the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt exception-specificationopt
as described in _dcl.fct_. A function shall be defined only in names
pace or class scope.
2 The parameters are in the scope of the outermost block of the func
tion-body.
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. ]
4 A ctor-initializer is used only in a constructor; see _class.ctor_ and
_class.init_.
5 A cv-qualifier-seq can be part of a non-static member function decla
ration, non-static member function definition, or pointer to member
function only; see _class.this_. It is part of the function type.
6 [Note: unused parameters need not be named. For example,
void print(int a, int)
{
printf("a = %d\n",a);
}
--end note]
8.5 Initializers [dcl.init]
1 A declarator can specify an initial value for the identifier being
declared. The identifier designates an object or reference being ini
tialized. The process of initialization described in the remainder of
this subclause (_dcl.init_) applies also to initializations specified
by other syntactic contexts, such as the initialization of function
parameters with argument expressions (_expr.call_) or the initializa
tion of return values (_stmt.return_).
initializer:
= initializer-clause
( expression-list )
initializer-clause:
assignment-expression
{ initializer-list ,opt }
{ }
initializer-list:
initializer-clause
initializer-list , initializer-clause
2 Automatic, register, static, and external variables of namespace scope
can be initialized by arbitrary expressions involving literals and
previously declared variables and functions. [Example:
int f(int);
int a = 2;
int b = f(a);
int c(b);
--end example]
3 [Note: default argument expressions are more restricted; see
_dcl.fct.default_.
4 The order of initialization of static objects is described in
_basic.start_ and _stmt.dcl_. ]
5 To zero-initialize storage for an object of type T means:
--if T is a scalar type (_basic.types_), the storage is set to the
value of 0 (zero) converted to T;
--if T is a non-union class type, the storage for each nonstatic data
member and each base-class subobject is zero-initialized;
--if T is a union type, the storage for its first data member5) is
_________________________
5) This member must not be static, by virtue of the requirements in
zero-initialized;
--if T is an array type, the storage for each element is zero-
initialized;
--if T is a reference type, no initialization is performed.
To default-initialize an object of type T means:
--if T is a non-POD class type (_class_), the default constructor for
T is called (and the initialization is ill-formed if T has no acces
sible default constructor);
--if T is an array type, each element is default-initialized;
--otherwise, the storage for the object is zero-initialized.
Default-initialization uses the direct-initialization semantics
described below.
6 The memory occupied by any object of static storage duration shall be
zero-initialized. Furthermore, if no initializer is explicitly speci
fied in the declaration of the object and the object is of non-POD
class type (or array thereof), then default initialization shall be
performed. If no initializer is specified for an object with auto
matic or dynamic storage duration, the object and its subobjects, if
any, have an indeterminate initial value.6)
7 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]
8 The form of initialization (using parentheses or =) is generally
insignificant, but does matter when the entity being initialized has a
class type; see below. A parenthesized initializer can be a list of
expressions only when the entity being initialized has a class type.
9 [Note: since () is not permitted by the syntax for initializer,
X a();
_________________________
_class.union_.
6) This does not apply to aggregate objects with automatic storage du
ration initialized with an incomplete brace-enclosed initializer-list;
see _dcl.init.aggr_.
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 per
mitted in certain other initialization contexts (_expr.new_,
_expr.type.conv_, _class.base.init_). ]
10The initialization that occurs in argument passing, function return,
throwing an exception (_except.throw_), handling an exception
(_except.handle_), and brace-enclosed initializer lists
(_dcl.init.aggr_) is called copy-initialization and is equivalent to
the form
T x = a;
The initialization that occurs in new expressions (_expr.new_),
static_cast expressions (_expr.static.cast_), functional notation type
conversions (_expr.type.conv_), and base and member initializers
(_class.base.init_) is called direct-initialization and is equivalent
to the form
T x(a);
11If T is a scalar type, then a declaration of the form
T x = { a };
is equivalent to
T x = a;
12The 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. The source type is
not defined when the initializer is brace-enclosed or when it is a
parenthesized list of expressions.
--If the destination type is a reference type, see _dcl.init.ref_.
--If the destination type is an array of characters or an array of
wchar_t, and the initializer is a string literal, see
_dcl.init.string_.
--Otherwise, if the destination type is an array, see _dcl.init.aggr_.
--If the destination type is a (possibly cv-qualified) class type:
--If the class is an aggregate (_dcl.init.aggr_), and the initial
izer is a brace-enclosed list, see _dcl.init.aggr_.
--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 des
tination, constructors are considered. The applicable construc
tors are enumerated (_over.match.ctor_), and the best one is cho
sen through overload resolution (_over.match_). The constructor
so selected is called to initialize the object, with the initial
izer expression(s) as its argument(s). If no constructor applies,
or the overload resolution is ambiguous, the initialization is
ill-formed.
--Otherwise (i.e., for the remaining copy-initialization cases), a
temporary is created. User-defined conversion sequences that can
convert from the source type to the destination type or a derived
class thereof are enumerated (_over.match.copy_), and the best one
is chosen through overload resolution (_over.match_). The user-
defined conversion so selected is called to convert the initial
izer expression into a temporary, whose type is the type returned
by the call of the user-defined conversion function, with the cv-
qualifiers of the destination type. If the conversion cannot be
done or is ambiguous, the initialization is ill-formed. The
object being initialized is then direct-initialized from the tem
porary according to the rules above.7) In certain cases, an imple
mentation is permitted to eliminate the temporary by initializing
the object directly; see _class.temporary_.
--Otherwise, if the source type is a (possibly cv-qualified) class
type, conversion functions are considered. The applicable conver
sion functions are enumerated (_over.match.conv_), and the best one
is chosen through overload resolution (_over.match_). 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.
--Otherwise, the initial value of the object being initialized is the
(possibly converted) value of the initializer expression. Standard
conversions (clause _conv_) will be used, if necessary, to convert
the initializer expression to the cv-unqualified version of the des
tination type; no user-defined conversions are considered. If the
conversion cannot be done, the initialization is ill-formed. [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]
8.5.1 Aggregates [dcl.init.aggr]
1 An aggregate is an array or a class (_class_) with no user-declared
constructors (_class.ctor_), no private or protected non-static data
members (_class.access_), no base classes (_class.derived_), and no
virtual functions (_class.virtual_).
2 When an aggregate is initialized the initializer can be an initial
izer-clause consisting of a brace-enclosed, comma-separated list of
initializers for the members of the aggregate, written in increasing
subscript or member order. If the aggregate contains subaggregates,
this rule applies recursively to the members of the subaggregate.
[Example:
_________________________
7) Because the type of the temporary is the same as the type of the
object being initialized, or is a derived class thereof, this direct-
initialization, if well-formed, will use a copy constructor
(_class.copy_) to copy the temporary.
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. ]
3 An aggregate that is a class can also be initialized with a single
expression not enclosed in braces, as described in _dcl.init_.
4 An array of unknown size initialized with a brace-enclosed initial
izer-list containing n initializers, where n shall be greater than
zero, is defined as having n elements (_dcl.array_). [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.
] An empty initializer list {} shall not be used as the initializer
for an array of unknown bound.8)
5 Static data members are not considered members of the class for pur
poses of aggregate initialization. [Example:
struct A {
int i;
static int s;
int j;
} a = { 1, 2 };
Here, the second initializer 2 initializes a.j and not the static data
member A::s. ]
6 An initializer-list is ill-formed if the number of initializers
exceeds the number of members or elements to initialize. [Example:
char cv[4] = { 'a', 's', 'd', 'f', 0 }; // error
is ill-formed. ]
7 If there are fewer initializers in the list than there are members in
the aggregate, then each member not explicitly initialized shall be
initialized with a value of the form T() (_expr.type.conv_), where T
represents the type of the uninitialized member. [Example:
struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };
initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of
an expression of the form int(), that is, 0. ]
8 An initializer for an aggregate member that is an empty class shall
have the form of an empty initializer-list {}. [Example:
_________________________
8) The syntax provides for empty initializer-lists, but nonetheless
C++ does not have zero length arrays.
struct S { };
struct A {
S s;
int i;
} a = { { } , 3 };
--end example] An empty initializer-list can be used to initialize
any aggregate. If the aggregate is not an empty class, then each mem
ber of the aggregate shall be initialized with a value of the form T()
(_expr.type.conv_), where T represents the type of the uninitialized
member.
9 If an incomplete or empty initializer-list leaves a member of refer
ence type uninitialized, the program is ill-formed.
10When initializing a multi-dimensional array, the initializers initial
ize the elements with the last (rightmost) index of the array varying
the fastest (_dcl.array_). [Example:
float y[4][3] = {
{ 1 }, { 2 }, { 3 }, { 4 }
};
initializes the first column of y (regarded as a two-dimensional
array) and leaves the rest zero. ]
11Braces can be elided in an initializer-list as follows. If the ini
tializer-list begins with a left brace, then the succeeding comma-
separated list of initializers initializes the members of a subaggre
gate; it is erroneous for there to be more initializers than members.
If, however, the initializer-list for a subaggregate does not begin
with a left brace, then only enough initializers from the list are
taken to initialize the members of the subaggregate; any remaining
initializers are left to initialize the next member of the aggregate
of which the current subaggregate is a member. [Example:
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
is a completely-braced initialization: 1, 3, and 5 initialize the
first row of the array y[0], namely y[0][0], y[0][1], and y[0][2].
Likewise the next two lines initialize y[1] and y[2]. The initializer
ends early and therefore y[3]'s elements are initialized as if explic
itly initialized with an expression of the form float(), that is, are
initialized with 0.0. In the following example, braces in the ini
tializer-list are elided; however the initializer-list has the same
effect as the completely-braced initializer-list of the above example,
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
The initializer for y begins with a left brace, but the one for y[0]
does not, therefore three elements from the list are used. Likewise
the next three are taken successively for y[1] and y[2]. --end exam
ple]
12All implicit type conversions (_conv_) are considered when initializ
ing the aggregate member with an initializer from an initializer-list.
If the initializer can initialize a member, the member is initialized.
Otherwise, if the member is itself a non-empty subaggregate, brace
elision is assumed and the initializer is considered for the initial
ization of the first member of the subaggregate. [Example:
struct A {
int i;
operator int();
};
struct B {
A a1, a2;
int z;
};
A a;
B b = { 4, a, a };
Braces are elided around the initializer for b.a1.i. b.a1.i is ini
tialized with 4, b.a2 is initialized with a, b.z is initialized with
whatever a.operator int() returns. ]
13[Note: An aggregate array or an aggregate class may contain members of
a class type with a user-declared constructor (_class.ctor_). Ini
tialization of these aggregate objects is described in
_class.expl.init_. ]
14When an aggregate is initialized with a brace-enclosed initializer-
list, if all the member initializer expressions are constant expres
sions, and the aggregate is a POD type, the initialization shall be
done during the static phase of initialization (_basic.start.init_);
otherwise, it is unspecified whether the initialization of members
with constant expressions takes place during the static phase or dur
ing the dynamic phase of initialization.
15When a union is initialized with a brace-enclosed initializer, the
braces shall only contain an initializer for the first member of the
union. [Example:
union u { int a; char* b; };
u a = { 1 };
u b = a;
u c = 1; // error
u d = { 0, "asdf" }; // error
u e = { "asdf" }; // error
--end example] [Note: as described above, the braces around the ini
tializer for a union member can be omitted if the union is a member of
another aggregate. ]
8.5.2 Character arrays [dcl.init.string]
1 A char array (whether plain char, signed, or unsigned) can be initial
ized by a string; a wchar_t array can be initialized by a wide string
literal; successive characters of the string initialize the members of
the array. [Example:
char msg[] = "Syntax error on line %s\n";
shows a character array whose members are initialized with a string.
Note that because '\n' is a single character and because a trailing
'\0' is appended, sizeof(msg) is 25. ]
2 There shall not be more initializers than there are array elements.
[Example:
char cv[4] = "asdf"; // error
is ill-formed since there is no space for the implied trailing '\0'.
]
8.5.3 References [dcl.init.ref]
1 A variable declared to be a T&, that is "reference to type T"
(_dcl.ref_), shall be initialized by an object, or function, of type T
or by an object that can be converted into a T. [Example:
int g(int);
void f()
{
int i;
int& r = i; // `r' refers to `i'
r = 1; // the value of `i' becomes 1
int* p = &r; // `p' points to `i'
int& rr = r; // `rr' refers to what `r' refers to,
// that is, to `i'
int (&rg)(int) = g; // `rg' refers to the function `g'
rg(i); // calls function `g'
int a[3];
int (&ra)[3] = a; // `ra' refers to the array `a'
ra[1] = i; // modifies `a[1]'
}
--end example]
2 A reference cannot be changed to refer to another object after ini
tialization. Note that initialization of a reference is treated very
differently from assignment to it. Argument passing (_expr.call_) and
function value return (_stmt.return_) are initializations.
3 The initializer can be omitted for a reference only in a parameter
declaration (_dcl.fct_), in the declaration of a function return type,
in the declaration of a class member within its class declaration
(_class.mem_), and where the extern specifier is explicitly used.
[Example:
int& r1; // error: initializer missing
extern int& r2; // ok
--end example]
4 Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related to
"cv2 T2" if T1 is the same type as T2, or T1 is a base class of T2.
"cv1 T1" is reference-compatible with "cv2 T2" if T1 is reference-
related to T2 and cv1 is the same cv-qualification as, or greater cv-
qualification than, cv2. For purposes of overload resolution, cases
for which cv1 is greater cv-qualification than cv2 are identified as
reference-compatible with added qualification (see _over.ics.rank_).
In all cases where the reference-related or reference-compatible rela
tionship of two types is used to establish the validity of a reference
binding, and T1 is a base class of T2, a program that necessitates
such a binding is ill-formed if T1 is an inaccessible (_class.access_)
or ambiguous (_class.member.lookup_) base class of T2.
5 A reference to type "cv1 T1" is initialized by an expression of type
"cv2 T2" as follows:
--If the initializer expression is an lvalue (but not an lvalue for a
bit-field), and
6
--"cv1 T1" is reference-compatible with "cv2 T2," or
--T2 is a class type, and the initializer expression can be implic
itly converted to an lvalue of type "cv3 T3," where T3 is the same
type as T2, or is a derived class thereof, and cv3 is the same cv-
qualification as, or lesser cv-qualification than, cv1 9) (this
conversion is selected by enumerating the applicable conversion
functions (_over.match.ref_) and choosing the best one through
overload resolution (_over.match_)), then
7 the reference is bound directly to the initializer expression lvalue
in the first case, and the reference is bound to the lvalue result
of the conversion in the second case. [Note: the usual lvalue-to-
rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-
to-pointer (_conv.func_) standard conversions are not needed, and
therefore are suppressed, when such direct bindings to lvalues are
done. ] [Example:
double d = 2.0;
double& rd = d; // rd refers to `d'
const double& rcd = d; // rcd refers to `d'
struct A { };
struct B : public A { } b;
A& ra = b; // ra refers to A sub-object in `b'
const A& rca = b; // rca refers to A sub-object in `b'
--end example]
8
--Otherwise, the reference shall be to a non-volatile const type
(i.e., cv1 shall be const). [Example:
double& rd2 = 2.0; // error: not an lvalue and reference
// not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference
// not const
--end example]
_________________________
9) This requires a conversion function (_class.conv.fct_) returning a
reference type.
--If the initializer expression is an rvalue, with T2 a class type,
and "cv1 T1" is reference-compatible with "cv2 T2," the reference
is bound in one of the following ways (the choice is implementa
tion-defined):
--The reference is bound directly to the object represented by the
rvalue (see _basic.lval_) or to a sub-object within that object.
--A temporary of type "cv1 T2" [sic] is created, and a copy con
structor is called to copy the entire rvalue object into the
temporary. The reference is bound to the temporary or to a sub-
object within the temporary.10)
9 The appropriate copy constructor must be callable whether or not
the copy is actually done. [Example:
struct A { };
struct B : public A { } b;
extern B f();
const A& rca = f(); // Either bound directly or
// the entire B object is copied and
// the reference is bound to the
// A sub-object of the copy
--end example]
10
--Otherwise, a temporary of type "cv1 T1" is created and initialized
from the initializer expression using the rules for a non-
reference copy initialization (_dcl.init_). The reference is then
bound to the temporary. If T1 is reference-related to T2, cv1
must be the same cv-qualification as, or greater cv-qualification
than, cv2; otherwise, the program is ill-formed. [Example:
const double& rcd2 = 2; // rcd2 refers to temporary
// with value `2.0'
const volatile int cvi = 1;
const int& r = cvi; // error: type qualifiers dropped
--end example]
11 [Note: _class.temporary_ describes the lifetime of temporaries bound
to references. ]
_________________________
10) Clearly, if the reference initialization being processed is one
for the first argument of a copy constructor call, an implementation
must eventually choose the direct-binding alternative to avoid infi
nite recursion.