______________________________________________________________________
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 fundamental type, storage class, or other
properties of the objects and functions being declared. The declara
tors specify the names of these objects and functions and (optionally)
modify the type 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)
4 Declarators have the syntax
declarator:
direct-declarator
ptr-operator declarator
_________________________
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 one declarator modifies the name environment
used by a following declarator, 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
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:
id-expression
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
or new, 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 func
tion 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. For 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 integer, pointer to integer, array of 3
pointers to integers, pointer to array of 3 integers, function having
no parameters and returning pointer to integer, and pointer to func
tion of double returning an integer.
2 A type can also be named (often more easily) by using a typedef
(_dcl.typedef_).
3 Note that an exception-specification does not affect the function
type, so its appearance in an abstract-declarator will have empty
semantics.
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, it surfaces as a choice
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 statements, the resolution
is to consider any construct that could possibly be a declaration a
declaration. A declaration can be explicitly disambiguated by a non
function-style cast or a = to indicate initialization. For example,
struct S {
S(int);
};
void foo(double a)
{
S x(int(a)); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
2 The ambiguity arising from the similarity between a function-style
cast and a type-id can occur in many different contexts. The ambigu
ity surfaces 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 For example,
#include <stddef.h>
char *p;
void *operator new(size_t, int);
void foo(int x) {
new (int(*p)) int; // new-placement expression
new (int(*[x])); // new type-id
}
4 For example,
template <class T>
struct S {
T *p;
};
S<int()> x; // type-id
S<int(1)> y; // expression (ill-formed)
5 For example,
void foo()
{
sizeof(int(1)); // expression
sizeof(int()); // type-id (ill-formed)
}
6 For example,
void foo()
{
(int(1)); // expression
(int())1; // type-id (ill-formed)
}
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. A declara
tor-id shall be a simple identifier, except for the following cases:
the declaration of some special functions (_class.conv_, _class.dtor_,
_over.oper_), the definition of a member function (_class.mfct_), the
definition of a static data member (_class.static_), the declaration
of a friend function that is a member of another class
(_class.friend_). An auto, static, extern, register, 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.
2 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
subsections give an inductive procedure for determining the type spec
ified for the contained declarator-id by such a declaration.
3 First, the decl-specifier-seq determines a type. For example, in the
declaration
int unsigned i;
the type specifiers int unsigned determine the type unsigned int
(_dcl.type.simple_). Or in general, in the declaration
T D
the decl-specifier-seq T determines the type T.
4 In a declaration T D where D is an unadorned identifier the type of
this identifier is T.
5 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 type-
modifier T, then the type of the identifier of D is type-modifier cv-
qualifier-seq pointer to T. The cv-qualifiers apply to the pointer
and not to the object pointed to.
2 For 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 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 an unqualified
pointer later, for example:
*ppc = &ci; // okay, but would make p point to ci ...
// ... because of previous error
*p = 5; // clobber ci
3 volatile specifiers are handled similarly.
4 See also _expr.ass_ and _dcl.init_.
5 There can be no pointers to references (_dcl.ref_) or pointers to bit-
fields (_class.bit_).
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 type-
modifier T, then the type of the identifier of D is type-modifier ref
erence to T. At all times during the determination of a type, types
of the form cv-qualified reference to T is adjusted to be reference to
T. For example, in
typedef int& A;
const A aref = 3;
the type of aref is reference to int, not const reference to int. A
declarator that specifies the type reference to cv void is ill-formed.
2 For 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.
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 A reference may or may not require storage (_basic.stc_).
4 There can be no references to references, no references to bit-fields
(_class.bit_), 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_) declara
tion within a class declaration, or is the declaration of an parameter
or a return type (_dcl.fct_); see _basic.def_. A reference shall be
initialized to refer to a valid object or function. In particular,
null references are prohibited; no diagnostic is required.
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 type-modifier T, then the type of
the identifier of D is type-modifier cv-qualifier-seq pointer to mem
ber of class nested-name-specifier of type T.
2 For 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
3 Note that a pointer to member cannot point to a static member of a
class (_class.static_), a member with reference type, or cv void.
There are no references to members. See also _expr.mptr.oper_ and
_expr.unary_.
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 type-
modifier T, then the type of the identifier of D is an array type. T
shall not be a reference type, an incomplete type, or an abstract
class type. If the constant-expression (_expr.const_) is present, 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 type-modifier array of N T. If
the constant expression is omitted, the type of the identifier of D is
type-modifier array of unknown bound of T, an incomplete object type.
The type type-modifier array of N T is a different type from the type
type-modifier array of unknown bound of T, see _basic.types_. Any cv-
qualifiers that appear in type-modifier are applied to the type T and
not to the array type, as in this example:
typedef int A[5], AA[2][3];
const A x; // type is ``array of 5 const int''
const AA y; // type is ``array of 2 array of 3 const int''
2 An array can be constructed from one of the fundamental types2)
(except void), from a pointer, from a pointer to member, from a class,
or from another array.
3 When several array of specifications are adjacent, a multidimensional
array is created; the constant expressions that specify the bounds of
the arrays can be omitted only for the first member of the sequence.
This elision is useful for function parameters of array types, and
when the array is external and the definition, which allocates stor
age, 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 The declaration
float fa[17], *afp[17];
declares an array of float numbers and an array of pointers to float
numbers. The declaration
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 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
_________________________
2) The enumeration types are included in the fundamental types.
pointed-to (n-1)-dimensional array, which itself is immediately con
verted into a pointer.
8 For 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 It follows from all this that arrays in C++ are stored row-wise (last
subscript varies fastest) and that the first subscript in the declara
tion 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
and the type of the contained declarator-id in the declaration T D1 is
type-modifier T1, the type of the declarator-id in D is type-modifier
cv-qualifier-seqopt function with parameters of type parameter-
declaration-clause and returning T1; a type of this form is a function
type3).
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. If the
parameter-declaration-clause terminates with an ellipsis, the number
of arguments is known only to be equal to or greater than the number
of parameters specified; if it is empty, the function takes no argu
ments. 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). Where
_________________________
3) As indicated by the syntax, cv-qualifiers are a significant compo
nent in function return types.
syntactically correct, , ... is synonymous with .... 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 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, several
transformations take place upon the types. Any cv-qualifier modifying
a parameter type is deleted; e.g., the type void(const int) becomes
void(int). Such cv-qualifiers affect only the definition of the
parameter within the body of the function. If the storage-class-
specifier register 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. The resulting list of transformed parameter types is
the function's parameter type list.
+------- BEGIN BOX 1 -------+
Issue: a definition for signature will be added as soon as the seman
tics are made precise.
+------- END BOX 1 -------+
The return type and the parameter type list, but not the default argu
ments (_dcl.fct.default_), are part of the function type. 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.4) A cv-qualifier-seq can only be part of a declaration or
definition of a nonstatic member function, and of a pointer to a mem
ber function; see _class.this_. It is part of the function type.
4 Functions cannot return arrays or functions, although they can return
pointers and references to such things. There are no arrays of func
tions, although there can be arrays of pointers to functions.
5 Types shall not be defined in return or parameter types.
6 The parameter-declaration-clause is used to check and convert argu
ments in calls and to check pointer-to-function and reference-to-
function assignments and initializations.
_________________________
4) 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 se
quence of pointer to and array of modifiers. This exclusion applies
to the parameters of the function, and if a parameter is a pointer to
function then to its parameters also, etc.
7 An identifier can optionally be provided as a parameter name; if pre
sent in a function declaration, it cannot be used since it goes out of
scope at the end of the function declarator (_basic.scope_); if pre
sent in a function definition (_dcl.fct.def_), it names a parameter
(sometimes called formal argument). In particular, parameter names
are also optional in function definitions and names used for a parame
ter in different declarations and the definition of a function need
not be the same.
8 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.
9 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);
10The declaration
fseek(FILE*, long, int);
declares a function taking three arguments of the specified types.
Since no return value type is specified it is taken to be int
(_dcl.type_). The declaration
printf(const char* ...);
declares a function that can be called with varying numbers and types
of arguments. For example,
printf("hello world");
printf("a=%d b=%d", a, b);
It shall always have a value, however, that can be converted to a
const char* as its first argument.
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 The declaration
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.5)
+------- BEGIN BOX 2 -------+
This restriction, voted in at the Valley Forge meeting, is expected to
be reviewed at the Austin meeting. Mike Miller has promised a paper.
+------- END BOX 2 -------+
4 Default arguments can be added in later declarations of a function,
but only 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, 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). For example:
_________________________
5) This means that default arguments cannot appear, for example, in
declarations of pointers to functions, references to functions, or
typedef declarations.
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)
}
Declarations of a given nonmember function in different translation
units need not specify the same default arguments. Declarations of a
given member function in different translation units, however, shall
specify the same default arguments (the accumulated sets of default
arguments at the end of the translation units shall be the same).
+------- BEGIN BOX 3 -------+
This was decided on the basis of guesses regarding the One Definition
Rule and should be reviewed once that section is finished.
+------- END BOX 3 -------+
5 Default argument expressions in non-member functions have their names
bound and their types checked at the point of declaration, and are
evaluated at each point of call. In member functions, names in
default argument expressions are bound at the end of the class decla
ration, like names in inline member function bodies (_class.inline_).
In the following example, 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))
}
}
Local variables shall not be used in default argument expressions.
For example,
void f()
{
int i;
extern void g(int x = i); // error
// ...
}
this shall not be used in a default argument of a member function.
For example,
class A {
void f(A* p = this); // error
};
6 Note that default arguments are evaluated before entry into a function
and that the order of evaluation of function arguments is implementa
tion dependent. 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. For exam
ple,
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: `float' called
int h(int a, int b = sizeof(a)); // error, parameter `a' used
// in default argument
7 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_). For
example, the declaration of X::mem1() in the following 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;
mem1(int i = a); // error: nonstatic member `a'
// used as default argument
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_.
8 A default argument is not part of the type of a function.
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
When a declaration of a function is introduced by way of a using dec
laration (_namespace.udecl_), any default argument information associ
ated with the declaration is imported as well.
+------- BEGIN BOX 4 -------+
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 4 -------+
9 An overloaded operator (_over.oper_) shall not have default arguments.
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. For 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->A::f(7)
pb->f(); // error: wrong number of arguments for B::f()
}
8.4 Function definitions [dcl.fct.def]
1 Function definitions have the form
function-definition:
decl-specifier-seqopt declarator ctor-initializeropt function-body
function-body:
compound-statement
The declarator in a function-definition shall have the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
as described in _dcl.fct_. A function can 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 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 that unused parameters need not be named. For example,
void print(int a, int)
{
printf("a = %d\n",a);
}
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 constants and
previously declared variables and functions.
int f(int);
int a = 2;
int b = f(a);
int c(b);
3 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 Variables with static storage duration (_basic.stc_) that are not ini
tialized and do not have a user-declared constructor are guaranteed to
start off as zero converted to the appropriate type. If the object is
a class or struct, its nonstatic data members start off as zero con
verted to the appropriate type. If the object is a union, its first
nonstatic data member starts off as zero converted to the appropriate
type. The initial values of automatic and register variables that are
not initialized are indeterminate.
6 An initializer for a static member is in the scope of the member's
class. For example,
int a;
struct X {
static int a;
static int b;
};
int X::a = 1;
int X::b = a; // X::b = X::a
7 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.
8 Note that since () is not an 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.
9 The initialization that occurs in argument passing and function return
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 equivalent to the form
T x(a);
10The 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 that
is an aggregate (_dcl.init.aggr_), and the initializer is a brace-
enclosed list, see _dcl.init.aggr_.
--Otherwise, if the destination type is a (possibly cv-qualified)
class type and the initializer has the parenthesized form, construc
tors are considered. The applicable constructors are enumerated
(_over.match.ctor_), and the best one is chosen through overload
resolution (_over.match_). The constructor so selected is called to
initialize the object, with the initializer expression(s) as its
argument(s). If no constructor applies, or the overload resolution
is ambiguous, the initialization is ill-formed.
--Otherwise, if the destination type or the source type is a (possibly
cv-qualified) class type, user-defined conversions are considered.
The applicable user-defined conversions are enumerated
(_over.match.user_), and the best one is chosen through overload
resolution (_over.match_). The user-defined conversion so selected
is called to copy or 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 unqualified version of the desti
nation type; no user-defined conversions are considered. If the
conversion cannot be done, the initialization is ill-formed. Note
that an expression of type cv1 T can initialize an object of type
cv2 T independently of the cv-qualifiers cv1 and cv2. For example,
int a;
const int b = a;
int c = b;
8.5.1 Aggregates [dcl.init.aggr]
1 An aggregate is an array or an object of a class (_class_) with no
user-declared constructors (_class.ctor_), no private or protected
members (_class.access_), no base classes (_class.derived_), and no
virtual functions (_class.virtual_). When an aggregate is initialized
the initializer can be an initializer-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. If there are fewer initializers in the
list than there are members of the aggregate, then the aggregate is
padded with zeros of the appropriate types.6)
2 For 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 zero.
3 An aggregate that is a class can also be initialized with a single
non-brace-enclosed expression, as described in _dcl.init_.
4 Braces can be elided as follows. If the initializer-clause begins
with a left brace, then the succeeding comma-separated list of ini
tializers initializes the members of the aggregate; it is erroneous
for there to be more initializers than members. If, however, the ini
tializer-clause or a subaggregate does not begin with a left brace,
then only enough elements from the list are taken to account for the
members of the aggregate; any remaining elements are left to initial
ize the next member of the aggregate of which the current aggregate is
a part.
5 For example,
int x[] = { 1, 3, 5 };
declares and initializes x as a one-dimensional array that has three
members, since no size was specified and there are three initializers.
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
is a completely-bracketed 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] is initialized with zeros. Precisely
the same effect could have been achieved by
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
The last (rightmost) index varies fastest (_dcl.array_).
6 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]. Also,
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.
_________________________
6) The syntax provides for empty initializer clauses, but nonetheless
C++ does not have zero length arrays.
7 Initialization of arrays of objects of a class with non-trivial con
structors (_class.ctor_) is described in _class.expl.init_.
8 The initializer for a union with no user-declared constructor is
either a single expression of the same type, or a brace-enclosed ini
tializer for the first member of the union. For 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
9 There shall not be more initializers than there are members or ele
ments to initialize. For example,
char cv[4] = { 'a', 's', 'd', 'f', 0 }; // error
is ill-formed.
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-
character string; successive characters of the string initialize the
members of the array. For 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.
For 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. For 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]'
}
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. For
example,
int& r1; // error: initializer missing
extern int& r2; // ok
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 relationship
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 bind
ing is ill-formed if T1 is an inaccessible (_class.access_) or ambigu
ous (_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
--the initializer expression can be implicitly converted to an
lvalue of type cv3 T1, where cv3 is the same cv-qualification as,
or lesser cv-qualification than, cv1, 7) then
_________________________
7) This requires a conversion function (_class.conv.fct_) returning a
7 the reference is bound directly to the initializer expression
lvalue. Note that 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.
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'
8
--Otherwise, the reference shall be to a non-volatile const type
(i.e., cv1 shall be const).
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
--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 implementation-
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. 8)
9 The appropriate copy constructor must be callable whether or not
the copy is actually done.
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
_________________________
reference type, and therefore applies only when T2 is a class type.
8) 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 infinite re
cursion.
10
--Otherwise, a temporary of type cv1 T1 is created and initialized
from the initializer expression using the rules for a non-
reference 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.
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
11 _class.temporary_ describes the lifetime of temporaries bound to
references.