______________________________________________________________________
5 Expressions [expr]
______________________________________________________________________
1 This clause defines the syntax, order of evaluation, and meaning of
expressions. An expression is a sequence of operators and operands
that specifies a computation. An expression may result in a value and
may cause side effects.
2 Operators can be overloaded, that is, given meaning when applied to
expressions of class type (_class_). Uses of overloaded operators are
transformed into function calls as described in _over.oper_. Over
loaded operators obey the rules for syntax specified in this clause,
but the requirements of operand type, lvalue, and evaluation order are
replaced by the rules for function call. Relations between operators,
such as ++a meaning a+=1, are not guaranteed for overloaded operators
(_over.oper_).1)
3 This clause defines the operators when applied to types for which they
have not been overloaded. Operator overloading cannot modify the
rules for operators applied to types for which they are defined by the
language itself.
4 Operators may be regrouped according to the usual mathematical rules
only where the operators really are associative or commutative. Over
loaded operators are never assumed to be associative or commutative.
Except where noted, the order of evaluation of operands of individual
operators and subexpressions of individual expressions is unspecified.
In particular, if a value is modified twice in an expression, the
result of the expression is unspecified except where an ordering is
guaranteed by the operators involved. For example,
i = v[i++]; // the value of `i' is undefined
i=7,i++,i++; // `i' becomes 9
5 The handling of overflow and divide by zero in expression evaluation
is implementation dependent. Most existing implementations of C++
ignore integer overflows. Treatment of division by zero and all
floating point exceptions vary among machines, and is usually
adjustable by a library function.
6 Except where noted, operands of types const T, volatile T, T&,
const T&, and volatile T& can be used as if they were of the plain
type T. Similarly, except where noted, operands of type T* const and
_________________________
1) Nor is it guaranteed for type bool; the left operand of += must not
have type bool.
T* volatile can be used as if they were of the plain type T*. Simi
larly, a plain T can be used where a volatile T or a const T is
required. These rules apply in combination so that, except where
noted, a T* const volatile can be used where a T* is required. Such
uses do not count as standard conversions when considering overloading
resolution (_over.match_), except when matching an object in a member
function call against the this parameter type.
7 If an expression initially has the type reference to T (_dcl.ref_,
_dcl.init.ref_), the type is adjusted to T prior to any further analy
sis, the expression designates the object or function denoted by the
reference, and the expression is an lvalue. A reference can be
thought of as a name of an object.
8 User-defined conversions of class objects to and from fundamental
types, pointers, and so on, can be defined (_class.conv_). If unam
biguous (_over.match_), such conversions will be applied by the com
piler wherever a class object appears as an operand of an operator or
as a function argument (_expr.call_).
9 Whenever an lvalue expression appears as an operand of an operator
that expects an rvalue for that operand, the lvalue-to-rvalue
(_conv.lval_), array-to-pointer (_conv.array_), or function-to-pointer
(_conv.func_) standard conversion will be applied to convert the
expression to an rvalue.
10Many binary operators that expect operands of arithmetic type cause
conversions and yield result types in a similar way. The purpose is
to yield a common type, which is also the type of the result. This
pattern is called the usual arithmetic conversions.
+------- BEGIN BOX 1 -------+
There are many places in this Clause that fail to treat enumerations
appropriately. Thus, for example, if e1 and e2 are of enumerated
type, e1+e2 is some kind of integer, and what kind depends on whether
e1 or e2 converts to long. The definition of ``usual arithmetic con
versions'' should take this into account.
+------- END BOX 1 -------+
11
--If either operand is of type long double, the other is converted to
long double.
--Otherwise, if either operand is double, the other is converted to
double.
--Otherwise, if either operand is float, the other is converted to
float.
--Otherwise, the integral promotions (_conv.prom_) are performed on
both operands.
--Then, if either operand is unsigned long the other is converted to
unsigned long.
--Otherwise, if one operand is a long int and the other unsigned int,
then if a long int can represent all the values of an unsigned int,
the unsigned int is converted to a long int; otherwise both operands
are converted to unsigned long int.
--Otherwise, if either operand is long, the other is converted to
long.
--Otherwise, if either operand is unsigned, the other is converted to
unsigned.
--Otherwise, both operands are int.
5.1 Primary expressions [expr.prim]
1 Primary expressions are literals, names, and names qualified by the
scope resolution operator ::.
primary-expression:
literal
this
:: identifier
:: operator-function-id
:: qualified-id
( expression )
id-expression
2 A literal is a primary expression. Its type depends on its form
(_lex.literal_).
3 In the body of a nonstatic member function (_class.mfct_), the keyword
this names a pointer to the object for which the function was invoked.
The keyword this cannot be used outside a class member function body.
+------- BEGIN BOX 2 -------+
In a constructor it is common practice to allow this in mem-
initializers.
+------- END BOX 2 -------+
4 The operator :: followed by an identifier, a qualified-id, or an oper
ator-function-id is a primary expression. Its type is specified by
the declaration of the identifier, name, or operator-function-id. The
result is the identifier, name, or operator-function-id. The result
is an lvalue if the identifier is. The identifier or operator-
function-id must be of file scope. Use of :: allows a type, an
object, a function, or an enumerator to be referred to even if its
identifier has been hidden (_basic.scope_).
5 A parenthesized expression is a primary expression whose type and
value are identical to those of the unadorned expression. The pres
ence of parentheses does not affect whether the expression is an
lvalue.
6 A id-expression is a restricted form of a primary-expression that can
appear after . and -> (_expr.ref_):
id-expression:
unqualified-id
qualified-id
unqualified-id:
identifier
operator-function-id
conversion-function-id
~ class-name
+------- BEGIN BOX 3 -------+
Issue: now it's allowed to invoke ~int(), but ~class-name doesn't
allow for that.
+------- END BOX 3 -------+
7 An identifier is an id-expression provided it has been suitably
declared (_dcl.dcl_). For operator-function-ids, see _over.oper_.
For conversion-function-ids, see _class.conv.fct_. A class-name pre
fixed by ~ denotes a destructor; see _class.dtor_.
qualified-id:
nested-name-specifier unqualified-id
8 A nested-name-specifier that names a class (_dcl.type_) followed by ::
and the name of a member of that class (_class.mem_), or a member of a
base of that class (_class.derived_), is a qualified-id; its type is
the type of the member. The result is the member. The result is an
lvalue if the member is. The class-name may be hidden by a nontype
name, in which case the class-name is still found and used. Where
class-name :: class-name is used, and the two class-names refer to the
same class, this notation names the constructor (_class.ctor_). Where
class-name :: ~ class-name is used, the two class-names must refer to
the same class; this notation names the destructor (_class.dtor_).
Multiply qualified names, such as N1::N2::N3::n, can be used to refer
to nested types (_class.nest_).
9 In a qualified-id, if the id-expression is a conversion-function-id,
its conversion-type-id shall denote the same type in both the context
in which the entire qualified-id occurs and in the context of the
class denoted by the nested-name-specifier. For the purpose of this
evaluation, the name, if any, of each class is also considered a
nested class member of that class.
5.2 Postfix expressions [expr.post]
1 Postfix expressions group left-to-right.
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( expression-listopt )
simple-type-specifier ( expression-listopt )
postfix-expression . id-expression
postfix-expression -> id-expression
postfix-expression ++
postfix-expression --
dynamic_cast < type-id > ( expression )
static_cast < type-id > ( expression )
reinterpret_cast < type-id > ( expression )
const_cast < type-id > ( expression )
typeid ( expression )
typeid ( type-id )
expression-list:
assignment-expression
expression-list , assignment-expression
5.2.1 Subscripting [expr.sub]
1 A postfix expression followed by an expression in square brackets is a
postfix expression. The intuitive meaning is that of a subscript.
One of the expressions must have the type pointer to T and the other
must be of enumeration or integral type. The result is an lvalue of
type T. The type T must be complete. The expression E1[E2] is iden
tical (by definition) to *((E1)+(E2)). See _expr.unary_ and
_expr.add_ for details of * and + and _dcl.array_ for details of
arrays.
5.2.2 Function call [expr.call]
1 There are two kinds of function call: ordinary function call and mem
ber function2) (_class.mfct_) call. A function call is a postfix
expression followed by parentheses containing a possibly empty, comma-
separated list of expressions which constitute the arguments to the
function. For ordinary function call, the postfix expression must be
a function name, or a pointer or reference to function. For member
function call, the postfix expression must be an implicit
(_class.mfct_) or explicit class member access (_expr.ref_) whose id-
expression is a function member name, or a pointer-to-member expres
sion (_expr.mptr.oper_) selecting a function member. The first
expression in the postfix expression is then called the object expres
sion, and the call is as a member of the object pointed to or referred
to. If a function or member function name is used, the name may be
overloaded (_over_), in which case the appropriate function will be
selected according to the rules in _over.match_. The function called
in a member function call is normally selected according to the static
type of the object expression (see _class.derived_), but if that func
tion is virtual the function actually called will be the final over
rider (_class.virtual_) of the selected function in the dynamic type
_________________________
2) A static member function (_class.static_) is an ordinary function.
of the object expression (i.e., the type of the object pointed or
referred to by the current value of the object expression).
2 The type of the function call expression is the return type of the
statically chosen function (i.e., ignoring the virtual keyword), even
if the type of the function actually called is different. This type
must be complete or the type void.
3 When a function is called, each parameter (_dcl.fct_) is initialized
(_dcl.init.ref_, _class.copy_, _class.ctor_) with its corresponding
argument. Standard (_conv_) and user-defined (_class.conv_) conver
sions are performed. The value of a function call is the value
returned by the called function except in a virtual function call if
the return type of the final overrider is different from the return
type of the statically chosen function, the value returned from the
final overrider is converted to the return type of the statically cho
sen function. A function may change the values of its nonconstant
parameters, but these changes cannot affect the values of the argu
ments except where a parameter is of a non-const reference type
(_dcl.ref_). Where a parameter is of reference type a temporary vari
able is introduced if needed (_dcl.type_, _lex.literal_, _lex.string_,
_dcl.array_, _class.temporary_). In addition, it is possible to mod
ify the values of nonconstant objects through pointer parameters.
4 A function may be declared to accept fewer arguments (by declaring
default arguments (_dcl.fct.default_)) or more arguments (by using the
ellipsis, ... _dcl.fct_) than the number of parameters in the func
tion definition (_dcl.fct.def_).
5 If no declaration of the called function is accessible from the scope
of the call the program is ill-formed. This implies that, except
where the ellipsis (...) is used, a parameter is available for each
argument.
6 Any argument of type float for which there is no parameter is con
verted to double before the call; any of char, short, or a bit-field
type for which there is no parameter are converted to int or unsigned
by integral promotion (_conv.prom_). Any argument of enumeration type
is converted to int, unsigned, long, or unsigned long by integral pro
motion. An object of a class for which no parameter is declared is
passed as a data structure.
+------- BEGIN BOX 4 -------+
To ``pass a parameter as a data structure'' means, roughly, that the
parameter must be a PODS, and that otherwise the behavior is unde
fined. This must be made more precise.
+------- END BOX 4 -------+
7 An object of a class for which a parameter is declared is passed by
initializing the parameter with the argument by a constructor call
before the function is entered (_class.temporary_, _class.copy_).
8 The order of evaluation of arguments is unspecified; take note that
compilers differ. All side effects of argument expressions take
effect before the function is entered. The order of evaluation of the
postfix expression and the argument expression list is unspecified.
9 The function-to-pointer standard conversion (_conv.func_) is sup
pressed on the postfix expression of a function call.
10Recursive calls are permitted.
11A function call is an lvalue if and only if the result type is a ref
erence.
5.2.3 Explicit type conversion (functional [expr.type.conv]
notation)
1 A simple-type-specifier (_dcl.type_) followed by a parenthesized
expression-list constructs a value of the specified type given the
expression list. If the expression list specifies a single value, the
expression is equivalent (in definedness, and if defined in meaning)
to the corresponding cast expression (_expr.cast_). If the expression
list specifies more than a single value, the type must be a class with
a suitably declared constructor (_dcl.init_, _class.ctor_).
2 A simple-type-specifier (_dcl.type_) followed by a (empty) pair of
parentheses constructs a value of the specified type. If the type is
a class with a default constructor (_class.ctor_), that constructor
will be called; otherwise the result is the default value given to a
static object of the specified type. See also (_expr.cast_).
5.2.4 Class member access [expr.ref]
1 A postfix expression followed by a dot .) or an arrow ->) followed by
an id-expression is a postfix expression. The postfix expression
before the dot or arrow is evaluated;3) the result of that evaluation,
together with the id-expression, determine the result of the entire
postfix expression.
2 For the first option (dot) the type of the first expression (the
object expression) shall be class object (of a complete type). For
the second option (arrow) the type of the first expression (the
pointer expression) shall be pointer to class object (of a complete
type). The id-expression shall name a member of that class, except
that an imputed destructor may be explicitly invoked for a built-in
type, see _class.dtor_. Therefore, if E1 has the type pointer to
class X, then the expression E1->E2 is converted to the equivalent
form (*(E1)).E2; the remainder of this subclause will address only the
first option (dot)4).
_________________________
3) This evaluation happens even if the result is unnecessary to deter
mine the value of the entire postfix expression, for example if the
id-expression denotes a static member.
4) Note that if E1 has the type pointer to class X, then (*(E1)) is an
lvalue.
3 If the id-expression is a qualified-id, the nested-name-specifier of
the qualified-id may specify a namespace name or a class name. If the
nested-name-specifier of the qualified-id specifies a namespace name,
the name is looked up in the context in which the entire postfix-
expression occurs. If nested-name-specifier of the qualified-id spec
ifies a class name, the class name is looked up as a type both in the
class of the object expression (or the class pointed to by the pointer
expression) and the context in which the entire postfix-expression
occurs. For the purpose of this type lookup, the name, if any, of
each class is also considered a nested class member of that class.
These searches shall yield a single type which might be found in
either or both contexts. If the nested-name-specifier contains a
class template-id (_temp.names_), its template-arguments are evaluated
in the context in which the entire postfix-expression occurs.
4 Similarly, if the id-expression is a conversion-function-id, its con
version-type-id shall denote the same type in both the context in
which the entire postfix-expression occurs and in the context of the
class of the object expression (or the class pointed to by the pointer
expression). For the purpose of this evaluation, the name, if any, of
each class is also considered a nested class member of that class.
5 Abbreviating object-expression.id-expression as E1.E2, then the type
and lvalue properties of this expression are determined as follows.
In the remainder of this subclause, cq represents either const or the
absence of const; vq represents either volatile or the absence of
volatile.
6 If E2 is declared to have type reference to T, then E1.E2 is an
lvalue; the type of E1.E2 is T. Otherwise, one of the following rules
applies.
--If E2 is a static data member, and the type of E2 is cq vq T, then
E1.E2 is an lvalue; the expression designates the named member of
the class. The type of E1.E2 is cq vq T.
--If E2 is a (possibly overloaded) static member function, and the
type of E2 is function of(parameter type list) returning T, then
E1.E2 is an lvalue; the expression designates the static member
function. The type of E1.E2 is the same type as that of E2, namely
cv-qualifier function of(parameter type list) returning T.
--If E2 is a non-static data member, and the type of E1 is cq1 vq1 X,
and the type of E2 is cq2 vq2 T, the expression designates the named
member of the object designated by the first expression. If E1 is
an lvalue, then E1.E2 is an lvalue. Let the notation vq12 stand for
the union of vq1 and vq2 ; that is, if vq1 or vq2 is volatile, then
vq12 is volatile. Similarly, let the notation cq12 stand for the
union of cq1 and cq2; that is, if cq1 or cq2 is const, then cq12 is
const. If E2 is declared to be a mutable member, then the type of
E1.E2 is vq12 T. If E2 is not declared to be a mutable member, then
the type of E1.E2 is cq12 vq12 T.
--If E2 is a (possibly overloaded) non-static member function, and the
type of E2 is cv-qualifier function of(parameter type list) return
ing T, then E1.E2 is not an lvalue. The expression designates a
member function (of some class X). The expression can be used only
as the left-hand operand of a member function call (_class.mfct_).
The member function shall be at least as cv-qualified as the left-
hand operand. The type of E1.E2 is class X's cv-qualifier member
function of(parameter type list) returning T.
--If E2 is a nested type, the expression E1.E2 is ill-formed.
--If E2 is a member constant, and the type of E2 is T, the expression
E1.E2 is not an lvalue. The type of E1.E2 is T.
7 Note that class objects can be structures (_class.mem_) and unions
(_class.union_). Classes are discussed in _class_.
5.2.5 Increment and decrement [expr.post.incr]
1 The value obtained by applying a postfix ++ is (a copy of) the value
that the operand had before applying the operator. The operand shall
be a modifiable lvalue. The type of the operand shall be an arith
metic type or a pointer to object type. After the result is noted,
the value of the object is modified by adding 1 to it, unless the
object is of type bool, in which case it is set to true (this use is
deprecated). The type of the result is the same as the type of the
operand, but it is not an lvalue. See also _expr.add_ and _expr.ass_.
2 The operand of postfix -- is decremented analogously to the postfix ++
operator, except that the operand shall not be of type bool.
5.2.6 Dynamic cast [expr.dynamic.cast]
1 The result of the expression dynamic_cast<T>(v) is of type T, which
shall be a pointer or a reference to a complete class type or pointer
to cv void. The type of v shall be a complete pointer type if T is a
pointer, or a complete reference type if T is a reference. Types
shall not be defined in a dynamic_cast. The dynamic_cast operator
cannot cast away constness (_expr.const.cast_).
2 If v has type T, the result is v. If T is a pointer to class B and v
is a pointer to class D such that B is an unambiguous accessible
direct or indirect base class of D, the result is a pointer to the
unique B sub-object of the D object pointed to by v. Similarly, if T
is a reference to class B and v is a reference to class D such that B
is an unambiguous accessible direct or indirect base class of D, the
result is a reference to the unique5) B sub-object of the D object
referred to by v. For example,
_________________________
5) The complete object pointed or referred to by v may contain other B
objects as base classes, but these are ignored.
struct B {};
struct D : B {};
void foo(D* dp)
{
B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
}
Otherwise v must be a pointer or reference to a polymorphic type
(_class.virtual_).
3 If T is cv-qualified void* then the result is a pointer to the com
plete object (_class.base.init_) pointed to by v. Otherwise, a run-
time check is applied to see if the object pointed or referred to by v
can be converted to the type pointed or referred to by T.
4 The run-time check logically executes like this: If, in the complete
object pointed (referred) to by v, v points (refers) to an unambiguous
base class sub-object of a T object, the result is a pointer (refer
ence) to that T object. Otherwise, if the type of the complete object
has an unambiguous public base class of type T, the result is a
pointer (reference) to the T sub-object of the complete object. Oth
erwise, the run-time check fails.
+------- BEGIN BOX 5 -------+
Comment from Bill Gibbons: the original papers allowed all strict
downcasts from accessible bases. This wording does not. The para
graph can be fixed by changing the first instance of ``an unambigu
ous'' to ``a public.''
+------- END BOX 5 -------+
5 The value of a failed cast to pointer type is the null pointer, as is
the result of applying const_cast to a null pointer. A failed cast to
reference type throws bad_cast (_lib.language.support_). For example,
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B {};
void g()
{
D d;
B* bp = (B*)&d; // cast needed to break protection
A* ap = &d; // public derivation, no cast needed
D& dr = dynamic_cast<D&>(*bp); // succeeds
ap = dynamic_cast<A*>(bp); // succeeds
bp = dynamic_cast<B*>(ap); // fails
ap = dynamic_cast<A*>(&dr); // succeeds
bp = dynamic_cast<B*>(&dr); // fails
}
class E : public D , public B {};
class F : public E, public D {}
void h()
{
F f;
A* ap = &f; // okay: finds unique A
D* dp = dynamic_cast<D*>(ap); // fails: ambiguous
E* ep = (E*)ap; // error: cast from virtual base
E* ep = dynamic_cast<E*>(ap); // succeeds
}
5.2.7 Type identification [expr.typeid]
1 The result of a typeid expression is of type const type_info&
(_lib.language.support_). The value is a reference to a type_info
object that represents the type-id or the type of the expression
respectively.
2 If the expression is a reference to a polymorphic type
(_class.virtual_) the type_info for the complete object
(_class.base.init_) referred to is the result. Where the expression
is a pointer to a polymorphic type dereferenced using * or [expres
sion] the type_info for the complete object pointed to is the result.
If the pointer is zero, the expression throws the bad_typeid exception
(_lib.language.support_). Otherwise, if the pointer does not point to
a valid object, the result is undefined.
3 If the expression is neither a pointer nor a reference to a polymor
phic type, the result is the type_info representing the (static) type
of the expression.
5.2.8 Static cast [expr.static.cast]
1 The result of the expression static_cast<T>(v) is of type T. Types
may not be defined in a static_cast. The conversions that may be per
formed explicitly using a static_cast are listed below. No other con
version may be performed explicitly using a static_cast.
2 The static_cast operator cannot cast away constness. See
_expr.const.cast_.
3 Any implicit conversion (including standard conversions and user-
defined conversions) can be performed explicitly using static_cast.
4 A value of integral type may be explicitly converted to an enumeration
type. The value is unchanged if the integral value is within the
range of the enumeration values (_dcl.enum_). Otherwise, the resulting
enumeration value is unspecified.
5 An rvalue of type pointer to cv B, where B is a complete class, can be
explicitly converted to an rvalue of type pointer to cv D, where D is
a complete class derived (_class.derived_) from B, if a valid pointer
conversion from pointer to cv D to pointer to cv B exists (_conv.ptr_)
and if B is not a virtual base class of D. Such a cast is valid only
if the rvalue of type pointer to cv B, points to a B that is actually
a sub-object of an object of type D; the resulting pointer points to
the enclosing object of type D. Otherwise (the rvalue of type pointer
to cv B does not point to a sub-object of an object of type D), the
result of the cast is undefined.
6 Aside from this pointer conversion (pointer-to-base to pointer-to-
derived), the inverse of any implicit conversion (_conv_) can be per
formed explicitly using static_cast subject to the restriction that
the explicit conversion does not cast away constness
(_expr.const.cast_).
7 The null pointer value (_conv.ptr_) is converted to the null pointer
value of the destination type.
8 An rvalue of type pointer to member of D of type cv T where D is a
class type, may be converted to an rvalue of type pointer to member of
B of type cv T, where B is a base class (_class.derived_) of D, if a
valid pointer conversion from pointer to cv D to pointer to cv B
exists (_conv.ptr_). The null member pointer value (_conv.mem_) is
converted to the null member pointer value of the destination type.
If the pointer to member converted is not the null member pointer
value and class B does not contain or inherit the original member, the
result of the cast is undefined.
9 An lvalue expression of type T1 may be cast to an lvalue of type T2
using the reference cast static_cast<T2&> if an expression of type
pointer to T1 may be explicitly converted to the type pointer to T2
using a static_cast.
10Constructors (_class.ctor_) or conversion functions (_class.conv_) are
not called as the result of a cast to a reference. Operations per
formed on the result of a pointer or reference cast refer to the same
object as the original (uncast) expression. That is, a reference cast
static_cast<T&>x has the same effect as the conversion
*static_cast<T*>&x with the built-in & and * operators. An implemen
tation shall not create a temporary when an lvalue is cast using a
reference cast. For example,
struct B {};
struct D : public B {};
D d;
// creating a temporary for the B sub-object not allowed
... (const B&) d ...
+------- BEGIN BOX 6 -------+
Is it possible to cast an rvalue to an lvalue using a reference cast?
An editorial box in this subclause used to say: [An rvalue expression
of type T may be explicitly converted to the type reference to const X
if a variable of type reference to const X can be initialized with an
rvalue expression of type T.] This is not true for lvalues. i.e. the
semantics for reference casts on lvalues are quite different from the
semantics of reference initialization using lvalues. Does it make
sense to have reference casts have different semantics depending on
whether they apply to lvalues or rvalues?
+------- END BOX 6 -------+
11The result of a reference cast is an lvalue; the results of other
casts are not.
12An expression may be converted to a class type (only) if an appropri
ate constructor or conversion operator has been declared
(_class.conv_).
13Any expression may be explicitly converted to type cv void
(_basic.type.qualifier_).
5.2.9 Reinterpret cast [expr.reinterpret.cast]
1 The result of the expression reinterpret_cast<T>(v) is of type T.
Types shall not be defined in reinterpret_cast. Conversions that can
be performed explicitly using reinterpret_cast are listed below. No
other conversion may be performed explicitly using reinterpret_cast.
2 The reinterpret_cast operator cannot cast away constness; see
_expr.const.cast_.
3 The mapping performed by reinterpret_cast is implementation-defined;
it may, or may not, produce a representation different from the origi
nal value.
4 A pointer can be explicitly converted to any integral type large
enough to hold it. The mapping function is implementation-defined,
but is intended to be unsurprising to those who know the addressing
structure of the underlying machine.
5 A value of integral type can be explicitly converted to a pointer. A
pointer converted to an integer of sufficient size (if any such exists
on the implementation) and back to the same pointer type will have its
original value; mappings between pointers and integers are otherwise
implementation-defined.
6 The operand of a pointer cast may be an rvalue of type pointer to
incomplete class type. The target type of a pointer cast may be
pointer to incomplete class type. In such cases, if there is any
inheritance relationship between the source and target classes, the
behavior is undefined.
7 A pointer to a function may be explicitly converted to a pointer to a
function of a different type. The effect of calling a function
through a pointer to a function type that differs from the type used
in the definition of the function is undefined. See also _conv.ptr_.
8 A pointer to an object can be explicitly converted to a pointer to an
object of different type. In general, the results of this are unspec
ified; except that converting an rvalue of type pointer to T1 to the
type pointer to T2 (where T1 and T2 are object types and where the
alignment requirements of T2 are no stricter than those of T1) and
back to its original type yields the original pointer value.
+------- BEGIN BOX 7 -------+
This does not allow conversion of function pointers to other function
pointer types and back. Should it?
+------- END BOX 7 -------+
9 The null pointer value (_conv.ptr_) is converted to the null pointer
value of the destination type.
10An rvalue of type pointer to member of X of type T1, may be explicitly
converted to an rvalue of type pointer to member of Y of type T2, if
T1 and T2 are both member function types or both data member types.
The null member pointer value (_conv.mem_) is converted to the null
member pointer value of the destination type. In general, the result
of this conversion is unspecified, except that:
--converting an rvalue of type pointer to member function to a differ
ent pointer to member function type and back to its original type
yields the original pointer to member value.
--converting an rvalue of type pointer to data member of X of type T1
to the type pointer to data member of Y of type T2 (where the align
ment requirements of T2 are no stricter than those of T1) and back
to its original type yields the original pointer to member value.
11Calling a member function through a pointer to member that represents
a function type that differs from the function type specified on the
member function declaration results in undefined behavior.
12An lvalue expression of type T1 may be cast to an lvalue of type T2
using the reference reinterpret_cast<T2&> if an rvalue of type pointer
to T1 may be explicitly converted to the type pointer to T2 with rein
terpret_cast.
13Constructors (_class.ctor_) or conversion functions (_class.conv_) are
not called as the result of a cast to a reference. Operations per
formed on the result of a pointer or reference cast refer to the same
object as the original (uncast) expression. That is, a reference cast
reinterpret_cast<T&>x has the same effect as the conversion *reinter
pret_cast<T*>&x with the built-in & and * operators. An implementa
tion shall not creat e a temporary when an lvalue is cast using a ref
erence cast.
14The result of a cast to a reference type is an lvalue; the results of
other casts are not.
5.2.10 Const cast [expr.const.cast]
1 The result of the expression const_cast<T>(v) is of type T. Types may
not be defined in a const_cast. Conversions that can be performed
explicitly using const_cast are listed below. No other conversion may
be performed explicitly using constcast.
2 An rvalue of type pointer to cv1 T may be explicitly converted to the
type pointer to cv2 T, where T is any object type and where cv1 is a
different cv-qualification from cv2, using the cast const_cast<cv2
T*>. An lvalue of type cv1 T may be explicitly converted to an lvalue
of type cv2 T, where T is any object type and where cv1 is a different
cv-qualification from cv2, using the cast const_cast<cv2 T&>. The
result of a pointer or reference const_cast refers to the original
object.
3 An rvalue of type pointer to member of X of type cv1 T may be explic
itly converted to the type pointer to member of X of type cv2 T, where
T is a data member type and where cv1 is a different cv-qualification
from cv2 using the cast const_cast<cv2 T X::*>. The result of a
pointer to member const_cast will refer to the same member as the
original (uncast) pointer to data member.
4 The following rules define casting away constness. In these rules Tn
and Xn represent types. For two pointer types:
Kismin(N,M)
casting from X1 to X2 casts away constness if, for a non-pointer type
T (e.g., int), there does not exist an implicit conversion from:
Tcv1,(N-K+1)*cv1,(N-K+2)*...cv1,N*
to
Tcv2,(N-K+1)*cv2,(M-K+2)*...cv2,M*
5 Casting from an lvalue of type T1 to an lvalue of type T2 using a ref
erence cast casts away constness if a cast from an rvalue of type
pointer to T1 to the type pointer to T2 casts away constness.
6 Casting from an rvalue of type "pointer to data member of X of type T1
to the type pointer to data member of Y of type T2 casts away const
ness if a cast from an rvalue of type pointer to T1 to the type
pointer to T2 casts away constness.
7 Note that these rules are not intended to protect constness in all
cases. For instance, conversions between pointers to functions are
not covered because such conversions lead to values whose use causes
undefined behavior. For the same reasons, conversions between point
ers to member functions, and in particular, the conversion from a
pointer to a const member function to a pointer to a non-const member
function, are not covered. For multi-level pointers to data members,
or multi-level mixed object and member pointers, the same rules apply
as for multi-level object pouinters. That is, the ``member of''
attribute is ignored for purposes of determining whether const has
been cast away.
8 Depending on the type of the object, a write operation through the
pointer, lvalue or pointer to data member resulting from a const_cast
that cast-away constness may produce undefined behavior
(_dcl.type.cv_).
+------- BEGIN BOX 8 -------+
This will need to be reworked once the memory model and object model
are ironed out.
+------- END BOX 8 -------+
9 A null pointer value (_conv.ptr_) is converted to the null pointer
value of the destination type. The null member pointer value
(_conv.mem_) is converted to the null member pointer value of the des
tination type.
5.3 Unary expressions [expr.unary]
1 Expressions with unary operators group right-to-left.
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
new-expression
delete-expression
unary-operator: one of
* & + - ! ~
5.3.1 Unary operators [expr.unary.op]
1 The unary * operator means indirection: the expression must be a
pointer, and the result is an lvalue referring to the object to which
the expression points. If the type of the expression is pointer to T,
the type of the result is T.
2 The result of the unary & operator is a pointer to its operand. The
operand must be an lvalue, or a qualified-id. In the first two cases,
if the type of the expression is T, the type of the result is pointer
to T. In particular, the address of an object of type cv T is pointer
to cv T, with the same cv-qualifiers. For example, the address of an
object of type const int has type pointer to const int. For a quali
fied-id, if the member is not static and of type T in class C, the
type of the result is pointer to member of class C of type T. For a
static member of type T, the type is plain pointer to T. Note that a
pointer to member is only formed when an explicit & is used and its
operand is a qualified-id not enclosed in parentheses. For example,
the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type pointer to member.
Neither does qualified-id, because there is no implicit conversion
from the type nonstatic member function to the type pointer to member
function, as there is from an lvalue of function type to the type
pointer to function (_conv.func_). Nor is &unqualified-id a pointer
to member, even within the scope of unqualified-id's class.
+------- BEGIN BOX 9 -------+
This section probably needs to take into account const and its
relationship to mutable.
+------- END BOX 9 -------+
3 The address of an object of incomplete type may be taken, but only if
the complete type of that object does not have the address-of operator
(operator&()) overloaded; no diagnostic is required.
4 The address of an overloaded function (_over_) can be taken only in a
context that uniquely determines which version of the overloaded func
tion is referred to (see _over.over_). Note that since the context
may determine whether the operand is a static or nonstatic member
function, the context may also affect whether the expression has type
pointer to function or pointer to member function.
5 The operand of the unary + operator shal have arithmetic, enumeration,
or pointer type and the result is the value of the argument. Integral
promotion is performed on integral or enumeration operands. The type
of the result is the type of the promoted operand.
6 The operand of the unary - operator shall have arithmetic or enumera
tion type and the result is the negation of its operand. Integral
promotion is performed on integral or enumeration operands. The nega
tive of an unsigned quantity is computed by subtracting its value from
2n, where n is the number of bits in the promoted operand. The type
of the result is the type of the promoted operand.
7 The operand of the logical negation operator ! is converted to bool
(_conv.bool_); its value is true if the converted operand is false and
false otherwise. The type of the result is bool.
8 The operand of ~ must have integral or enumeration type; the result is
the one's complement of its operand. Integral promotions are per
formed. The type of the result is the type of the promoted operand.
5.3.2 Increment and decrement [expr.pre.incr]
1 The operand of prefix ++ is modified by adding 1, or set to true if it
is bool (this use is deprecated). The operand shall be a modifiable
lvalue. The type of the operand shall be an arithmetic type or a
pointer to a completely-defined object type. The value is the new
value of the operand; it is an lvalue. If x is not of type bool, the
expression ++x is equivalent to x+=1. See the discussions of addition
(_expr.add_) and assignment operators (_expr.ass_) for information on
conversions.
2 The operand of prefix -- is decremented analogously to the prefix ++
operator, except that the operand shall not be of type bool.
5.3.3 Sizeof [expr.sizeof]
1 The sizeof operator yields the size, in bytes, of its operand. The
operand is either an expression, which is not evaluated, or a paren
thesized type-id. The sizeof operator may not be applied to an
expression that has function or incomplete type, or to the parenthe
sized name of such a type, or to an lvalue that designates a bit-
field. A byte is unspecified by the language except in terms of the
value of sizeof; sizeof(char) is 1, but sizeof(bool) and
sizeof(wchar_t) are implementation-defined. 6)
2 When applied to a reference, the result is the size of the referenced
object. When applied to a class, the result is the number of bytes in
an object of that class including any padding required for placing
such objects in an array. The size of any class or class object is
greater than zero. When applied to an array, the result is the total
number of bytes in the array. This implies that the size of an array
of n elements is n times the size of an element.
3 The sizeof operator may be applied to a pointer to a function, but not
to a function.
4 The lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_),
and function-to-pointer (_conv.func_) standard conversions are sup
pressed on the operand of sizeof.
5 Types may not be defined in a sizeof expression.
6 The result is a constant of type size_t, an implementation-dependent
unsigned integral type defined in the standard header <cstddef>.
5.3.4 New [expr.new]
1 The new-expression attempts to create an object of the type-id
(_dcl.name_) to which it is applied. This type shall be a complete
object or array type (_intro.memory_, _basic.types_).
new-expression:
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt
new-placement:
( expression-list )
new-type-id:
type-specifier-seq new-declaratoropt
new-declarator:
* cv-qualifier-seqopt new-declaratoropt
::opt nested-name-specifier * cv-qualifier-seqopt new-declaratoropt
direct-new-declarator
direct-new-declarator:
[ expression ]
direct-new-declarator [ constant-expression ]
new-initializer:
( expression-listopt )
Entities created by a new-expression have dynamic storage duration
(_basic.stc.dynamic_). That is, the lifetime of such an entity is not
restricted to the scope in which it is created. If the entity is an
object, the new-expression returns a pointer to the object created.
_________________________
6) sizeof(bool) is not required to be 1.
If it is an array, the new-expression returns a pointer to the initial
element of the array.
2 The new-type in a new-expression is the longest possible sequence of
new-declarators. This prevents ambiguities between declarator opera
tors &, *, [], and their expression counterparts. For example,
new int*i; // syntax error: parsed as `(new int*) i'
// not as `(new int)*i'
The * is the pointer declarator and not the multiplication operator.
3 Parenthese must not appear in a new-type-id used as the operand for
new. For example,
4 new int(*[10])(); // error
is ill-formed because the binding is
(new int) (*[10])(); // error
The explicitly parenthesized version of the new operator can be used
to create objects of compound types (_basic.compound_). For example,
new (int (*[10])());
allocates an array of 10 pointers to functions (taking no argument and
returning int).
5 The type-specifier-seq shall not contain const, volatile, class decla
rations, or enumeration declarations.
6 When the allocated object is an array (that is, the direct-new-
declarator syntax is used or the new-type-id or type-id denotes an
array type), the new-expression yields a pointer to the initial ele
ment (if any) of the array. Thus, both new int and new int[10] return
an int* and the type of new int[i][10] is int (*)[10].
7 Every constant-expression in a direct-new-declarator shall be an inte
gral constant expression (_expr.const_) with a strictly positive
value. The expression in a direct-new-declarator shall be of integral
type (_basic.fundamental_) with a non-negative value. For example, if
n is a variable of type int, then new float[n][5] is well-formed
(because n is the expression of a direct-new-declarator), but
new float[5][n] is ill-formed (because n is not a constant-
expression). If n is negative, the effect of new float[n][5] is unde
fined.
8 When the value of the expression in a direct-new-declarator is zero,
an array with no elements is allocated. The pointer returned by the
new-expression will be non-null and distinct from the pointer to any
other object.
9 Storage for the object created by a new-expression is obtained from
the appropriate allocation function (_basic.stc.dynamic.allocation_).
When the allocation function is called, the first argument will be
amount of space requested (which may be larger than the size of the
object being created only if that object is an array).
10An implementation provides default definitions of the global alloca
tion functions operator new() for non-arrays (_lib.op.new_) and
operator new[]() for arrays (_lib.op.new.array_). A C++ program may
provide alternative definitions of these functions
(_lib.alternate.definitions.for.functions_), and/or class-specific
versions (_class.free_).
11The new-placement syntax can be used to supply additional arguments to
an allocation function. Overloading resolution is done by assembling
an argument list from the amount of space requested (the first argu
ment) and the expressions in the new-placement part of the new-
expression, if used (the second and succeeding arguments).
12For example:
--new T results in a call of operator new(sizeof(T)),
--new(2,f) T results in a call of operator new(sizeof(T),2,f),
--new T[5] results in a call of operator new[](x), and
--new(2,f) T[5] results in a call of operator new[](y,2,f).
13The return value from the allocation function, if non-null, will be
assumed to point to a block of appropriately aligned available storage
of the requested size, and the object will be created in that block
(but not necessarily at the beginning of the block, if the object is
an array).
14If a class has one or more constructors (_class.ctor_), a new-
expression for that class calls one of them to initialize the object.
An object of a class can be created by new only if suitable arguments
are provided to the class' constructors, or if the class has a default
constructor (_basic.def_).7) If the class does not have a default con
structor, suitable arguments (_over.match_) must be provided in a new-
initializer. If there is no constructor and a new-initializer is
used, it must be of the form (expression) or (). If an expression is
present it will be used to initialize the object; if not, or a new-
initializer is not used, the object will start out with an unspecified
value.
15No initializers can be specified for arrays. Arrays of objects of a
class can be created by a new-expression only if the class has a
default constructor.8) In that case, the default constructor will be
called for each element of the array, in order of increasing address.
16Access and ambiguity control are done for both the allocation function
and the constructor (_class.ctor_, _class.free_).
17The allocation function may indicate failure by throwing an alloc
exception (_except_, _lib.alloc_). In this case no initialization is
_________________________
7) This means that struct s{}; s* ps = new s; is allowed on the
grounds that class s has an implicitly declared constructor.
8) PODS structs have an implicitly-declared default constructor.
done.
18If the constructor throws an exception and the new-expression does not
contain a new-placement, then the deallocation function
(_basic.stc.dynamic.deallocation_, _class.free_) is used to free the
memory in which the object was being constructed, after which the
exception continues to propagate in the context of the new-expression.
19The way the object was allocated determines how it is freed: if it is
allocated by ::new, then it is freed by ::delete, and if it is an
array, it is freed by delete[] or ::delete[] as appropriate.
+------- BEGIN BOX 10 -------+
This is a correction to San Diego resolution 3.5, which on its face
seems to require that whether to use delete or delete[] must be
decided purely on syntactic grounds. I believe the intent of the com
mittee was to make the form of delete correspond to the form of the
corresponding new.
+------- END BOX 10 -------+
20Whether the allocation function is called before evaluating the con
structor arguments, after evaluating the constructor arguments but
before entering the constructor, or by the constructor itself is
unspecified. It is also unspecified whether the arguments to a con
structor are evaluated if the allocation function returns the null
pointer or throws an exception.
5.3.5 Delete [expr.delete]
1 The delete-expression operator destroys a complete object
(_intro.memory_) or array created by a new-expression.
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
The first alternative is for non-array objects, and the second is for
arrays. The result has type void.
2 In either alternative, if the value of the operand of delete is the
null pointer the operation has no effect. Otherwise, in the first
alternative (delete object), the value of the operand of delete shall
be a pointer to a non-array object created by a new-expression without
a new-placement specification, or a pointer to a sub-object
(_intro.memory_) representing a base class of such an object
(_class.derived_).
+------- BEGIN BOX 11 -------+
Issue: ... or a class with an unambiguous conversion to such a pointer
type ...
+------- END BOX 11 -------+
In the second alternative (delete array), the value of the operand of
delete shall be a pointer to an array created by a new-expression
without a new-placement specification.
3 In the first alternative (delete object), if the static type of the
operand is different from its dynamic type, the static type must have
a virtual destructor or the result is undefined. In the second alter
native (delete array) if the dynamic type of the object to be deleted
is a class that has a destructor and its static type is different from
its dynamic type, the result is undefined.
+------- BEGIN BOX 12 -------+
This should probably be tightened to require that the static and
dynamic types match, period.
+------- END BOX 12 -------+
4 The deletion of an object may change its value. If the expression
denoting the object in a delete-expression is a modifiable lvalue, any
attempt to access its value after the deletion is undefined
(_basic.stc.dynamic.deallocation_).
5 A C++ program that applies delete to a pointer to constant is ill-
formed (_intro.compliance_, _intro.execution_).
6 If the class of the object being deleted is incomplete at the point of
deletion and the class has a destructor or an allocation function or a
deallocation function, the result is undefined.
7 The delete-expression will invoke the destructor (if any) for the
object or the elements of the array being deleted. In the case of an
array, the elements will be destroyed in order of decreasing address
(that is, in reverse order of construction).
8 To free the storage pointed to, the delete-expression will call a
deallocation function (_basic.stc.dynamic.deallocation_).
9 An implementation provides default definitions of the global dealloca
tion functions operator delete() for non-arrays (_lib.op.delete_) and
operator delete[]() for arrays (_lib.op.delete.array_). A C++ program
may provide alternative definitions of these functions
(_lib.alternate.definitions.for.functions_), and/or class-specific
versions (_class.free_).
10Access and ambiguity control are done for both the deallocation func
tion and the destructor (_class.dtor_, _class.free_).
5.4 Explicit type conversion (cast notation) [expr.cast]
1 The result of the expression (T) cast-expression is of type T. An
explicit type conversion can be expressed using functional notation
(_expr.type.conv_), a type conversion operator (dynamic_cast,
static_cast, reinterpret_cast, const_cast), or the cast notation.
cast-expression:
unary-expression
( type-id ) cast-expression
2 Types may not be defined in casts.
3 Any type conversion not mentioned below and not explicitly defined by
the user (_class.conv_) is ill-formed.
4 The conversions performed by static_cast (_expr.static.cast_), rein
terpret_cast (_expr.reinterpret.cast_), const_cast
(_expr.const.cast_), or any sequence thereof, may be performed using
the cast notation of explicit type conversion. The same semantic
restrictions and behaviors apply.
5 In addition to those conversions, a pointer to an object of a derived
class (_class.derived_) may be explicitly converted to a pointer to
any of its base classes regardless of accessibility restrictions
(_class.access.base_), provided the conversion is unambiguous
(_class.member.lookup_). The resulting pointer will refer to the con
tained object of the base class.
5.5 Pointer-to-member operators [expr.mptr.oper]
1 The pointer-to-member operators ->* and .* group left-to-right.
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression
2 The binary operator .* binds its second operand, which must be of
type pointer to member of T to its first operand, which must be of
class T or of a class of which T is an unambiguous and accessible base
class. The result is an object or a function of the type specified by
the second operand.
3 The binary operator ->* binds its second operand, which must be of
type pointer to member of T to its first operand, which must be of
type pointer to T or pointer to a class of which T is an unambiguous
and accessible base class. The result is an object or a function of
the type specified by the second operand.
4 If the result of .* or ->* is a function, then that result can be
used only as the operand for the function call operator (). For exam
ple,
(ptr_to_obj->*ptr_to_mfct)(10);
calls the member function denoted by ptr_to_mfct for the object
pointed to by ptr_to_obj. The result of a .* expression is an lvalue
only if its first operand is an lvalue and its second operand is a
pointer to data member. The result of an ->* expression is an lvalue
only if its second operand is a pointer to data member. If the second
operand is the null pointer to member value (_conv.mem_), the result
is undefined.
5.6 Multiplicative operators [expr.mul]
1 The multiplicative operators *, /, and % group left-to-right.
multiplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
2 The operands of * and / must have arithmetic type; the operands of %
must have integral type. The usual arithmetic conversions
(_conv.arith_) are performed on the operands and determine the type of
the result.
3 The binary * operator indicates multiplication.
4 The binary / operator yields the quotient, and the binary % operator
yields the remainder from the division of the first expression by the
second. If the second operand of / or % is zero the result is unde
fined; otherwise (a/b)*b + a%b is equal to a. If both operands are
nonnegative then the remainder is nonnegative; if not, the sign of the
remainder is implementation dependent.
5.7 Additive operators [expr.add]
1 The additive operators + and - group left-to-right. The usual arith
metic conversions (_conv.arith_) are performed for operands of arith
metic type.
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
For addition, either both operands shall have arithmetic type, or one
operand shall be a pointer to a completely defined object type and the
other shall have integral type.
2 For subtraction, one of the following shall hold:
--both operands have arithmetic type;
--both operands are pointers to qualified or unqualified versions of
the same completely defined object type; or
--the left operand is a pointer to a completely defined object type
and the right operand has integral type.
3 If both operands have arithmetic type, the usual arithmetic conver
sions are performed on them. The result of the binary + operator is
the sum of the operands. The result of the binary - operator is the
difference resulting from the subtraction of the second operand from
the first.
4 For the purposes of these operators, a pointer to a nonarray object
behaves the same as a pointer to the first element of an array of
length one with the type of the object as its element type.
5 When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If
the pointer operand points to an element of an array object, and the
array is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integral expression.
In other words, if the expression P points to the i-th element of an
array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N
(where N has the value n) point to, respectively, the i+n-th and i-n-
th elements of the array object, provided they exist. Moreover, if
the expression P points to the last element of an array object, the
expression (P)+1 points one past the last element of the array object,
and if the expression Q points one past the last element of an array
object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined. If the result is used as an operand of the
unary * operator, the behavior is undefined unless both the pointer
operand and the result point to elements of the same array object, or
the pointer operand points one past the last element of an array
object and the result points to an element of the same array object.
6 When two pointers to elements of the same array object are subtracted,
the result is the difference of the subscripts of the two array ele
ments. The type of the result is an implementation-defined signed
integral type; this type shall be the same type that is defined as
ptrdiff_t in the <cstddef> header (_lib.language.support_). As with
any other arithmetic overflow, if the result does not fit in the space
provided, the behavior is undefined. In other words, if the expres
sions P and Q point to, respectively, the i-th and j-th elements of an
array object, the expression (P)-(Q) has the value i-j provided the
value fits in an object of type ptrdiff_t. Moreover, if the expres
sion P points either to an element of an array object or one past the
last element of an array object, and the expression Q points to the
last element of the same array object, the expression ((Q)+1)-(P) has
the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value
zero if the expression P points one past the last element of the array
object, even though the expression (Q)+1 does not point to an element
of the array object. Unless both pointers point to elements of the
same array object, or one past the last element of the array object,
the behavior is undefined.9)
_________________________
9) Another way to approach pointer arithmetic is first to convert the
pointer(s) to character pointer(s): In this scheme the integral ex
pression added to or subtracted from the converted pointer is first
multiplied by the size of the object originally pointed to, and the
resulting pointer is converted back to the original type. For pointer
subtraction, the result of the difference between the character point
ers is similarly divided by the size of the object originally pointed
to.
5.8 Shift operators [expr.shift]
1 The shift operators << and >> group left-to-right.
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
The operands must be of integral type and integral promotions are per
formed. The type of the result is that of the promoted left operand.
The result is undefined if the right operand is negative, or greater
than or equal to the length in bits of the promoted left operand. The
value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2
bits; vacated bits are zero-filled. The value of E1 >> E2 is E1
right-shifted E2 bit positions. The right shift is guaranteed to be
logical (zero-fill) if E1 has an unsigned type or if it has a nonnega
tive value; otherwise the result is implementation dependent.
5.9 Relational operators [expr.rel]
1 The relational operators group left-to-right, but this fact is not
very useful; a<b<c means (a<b)<c and not (a<b)&&(b<c).
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
The operands must have arithmetic or pointer type. The operators <
(less than), > (greater than), <= (less than or equal to), and >=
(greater than or equal to) all yield false or true. The type of the
result is bool.
2 The usual arithmetic conversions are performed on arithmetic operands.
Pointer conversions are performed on pointer operands to bring them to
the same type, which must be a qualified or unqualified version of the
type of one of the operands. This implies that any pointer may be
compared to an integral constant expression evaluating to zero and any
pointer can be compared to a pointer of qualified or unqualified type
void* (in the latter case the pointer is first converted to void*).
Pointers to objects or functions of the same type (after pointer con
versions) may be compared; the result depends on the relative posi
tions of the pointed-to objects or functions in the address space.
3 If two pointers of the same type point to the same object or function,
or both point one past the end of the same array, or are both null,
they compare equal. If two pointers of the same type point to differ
ent objects or functions, or only one of them is null, they compare
unequal. If two pointers point to nonstatic data members of the same
_________________________
7 When viewed in this way, an implementation need only provide one extra
byte (which may overlap another object in the program) just after the
end of the object in order to satisfy the one past the last element
requirements.
object, the pointer to the later declared member compares higher pro
vided the two members not separated by an access-specifier label
(_class.access.spec_) and provided their class is not a union. If two
pointers point to nonstatic members of the same object separated by an
access-specifier label (_class.access.spec_) the result is unspeci
fied. If two pointers point to data members of the same union, they
compare equal (after conversion to void*, if necessary). If two
pointers point to elements of the same array or one beyond the end of
the array, the pointer to the object with the higher subscript com
pares higher. Other pointer comparisons are implementation-defined.
5.10 Equality operators [expr.eq]
1 equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
The == (equal to) and the != (not equal to) operators have the same
semantic restrictions, conversions, and result type as the relational
operators except for their lower precedence and truth-value result.
(Thus a<b == c<d is true whenever a<b and c<d have the same truth-
value.)
2 In addition, pointers to members of the same type may be compared.
Pointer to member conversions (_conv.mem_) are performed. A pointer
to member may be compared to an integral constant expression that
evaluates to zero. If one operand is a pointer to a virtual member
function and the other is not the null pointer to member value, the
result is unspecified.
5.11 Bitwise AND operator [expr.bit.and]
1 and-expression:
equality-expression
and-expression & equality-expression
The usual arithmetic conversions are performed; the result is the bit
wise function of the operands. The operator applies only to integral
operands.
5.12 Bitwise exclusive OR operator [expr.xor]
1 exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
The usual arithmetic conversions are performed; the result is the bit
wise exclusive function of the operands. The operator applies only to
integral operands.
5.13 Bitwise inclusive OR operator [expr.or]
1 inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression
The usual arithmetic conversions are performed; the result is the
bitwise inclusive function of its operands. The operator applies only
to integral operands.
5.14 Logical AND operator [expr.log.and]
1 logical-and-expression:
inclusive-or-expression
logical-and-expression && inclusive-or-expression
The && operator groups left-to-right. The operands are both converted
to type bool (_conv.bool_). The result is true if both operands are
true and false otherwise. Unlike &, && guarantees left-to-right eval
uation: the second operand is not evaluated if the first operand is
false.
2 The result is a bool. All side effects of the first expression except
for destruction of temporaries (_class.temporary_) happen before the
second expression is evaluated.
5.15 Logical OR operator [expr.log.or]
1 logical-or-expression:
logical-and-expression
logical-or-expression || logical-and-expression
The || operator groups left-to-right. The operands are both converted
to bool (_conv.bool_). It returns true if either of its operands is
true, and false otherwise. Unlike |, || guarantees left-to-right
evaluation; moreover, the second operand is not evaluated if the first
operand evaluates to true.
2 The result is a bool. All side effects of the first expression except
for destruction of temporaries (_class.temporary_) happen before the
second expression is evaluated.
5.16 Conditional operator [expr.cond]
1 conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
Conditional expressions group right-to-left. The first expression is
converted to bool (_conv.bool_). It is evaluated and if it is true,
the result of the conditional expression is the value of the second
expression, otherwise that of the third expression. All side effects
of the first expression except for destruction of temporaries
(_class.temporary_) happen before the second or third expression is
evaluated.
2 If either the second or third expression is a throw-expression
(_except.throw_), the result is of the type of the other.
3 If both the second and the third expressions are of arithmetic type,
then if they are of the same type the result is of that type; other
wise the usual arithmetic conversions are performed to bring them to a
common type. Otherwise, if both the second and the third expressions
are either a pointer or an integral constant expression that evaluates
to zero, pointer conversions (_conv.ptr_) are performed to bring them
to a common type which must be a qualified or unqualified version of
the type of either the second or the third expression. Otherwise, if
both the second and the third expressions are either a pointer to mem
ber or an integral constant expression that evaluates to zero, pointer
to member conversions (_conv.mem_) are performed to bring them to a
common type10) which must be a qualified or unqualified version of the
type of either the second or the third expression. Otherwise, if both
the second and the third expressions are lvalues of related class
types, they are converted to a common type as if by a cast to a refer
ence to the common type (_expr.static.cast_). Otherwise, if both the
second and the third expressions are of the same class T, the common
type is T. Otherwise, if both the second and the third expressions
have type cv void, the common type is cv void. Otherwise the expres
sion is ill formed. The result has the common type; only one of the
second and third expressions is evaluated. The result is an lvalue if
the second and the third operands are of the same type and both are
lvalues.
5.17 Assignment operators [expr.ass]
1 There are several assignment operators, all of which group right-to-
left. All require a modifiable lvalue as their left operand, and the
type of an assignment expression is that of its left operand. The
result of the assignment operation is the value stored in the left
operand after the assignment has taken place; the result is an lvalue.
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
throw-expression
assignment-operator: one of
= *= /= %= += -= >>= <<= &= ^= |=
2 In simple assignment (=), the value of the expression replaces that of
the object referred to by the left operand.
3 If the left operand is not of class type, the expression is converted
to the unqualified type of the left operand using standard conversions
(_conv_) and/or user-defined conversions (_class.conv_), as necessary.
4 Assignment to objects of a class (_class_) X is defined by the func
tion X::operator=() (_over.ass_). Unless the user defines an
X::operator=(), the default version is used for assignment
(_class.copy_). This implies that an object of a class derived from X
(directly or indirectly) by unambiguous public derivation
(_class.derived_) can be assigned to an X.
5 For class objects, assignment is not in general the same as initial
ization (_dcl.init_, _class.ctor_, _class.init_, _class.copy_).
_________________________
10) This is one instance in which the composite type, as described in
the C Standard, is still employed in C++.
6 When the left operand of an assignment operator denotes a reference to
T, the operation assigns to the object of type T denoted by the refer
ence.
7 The behavior of an expression of the form E1 op= E2 is equivalent to
E1=E1 op E2 except that E1 is evaluated only once. E1 shall not have
bool type. In += and -=, E1 can be a pointer to a possibly-qualified
completely defined object type, in which case E2 shall have integral
type and is converted as explained in _expr.add_; In all other cases,
E1 and E2 shall have arithmetic type.
8 See _except.throw_ for throw expressions.
5.18 Comma operator [expr.comma]
1 The comma operator groups left-to-right.
expression:
assignment-expression
expression , assignment-expression
A pair of expressions separated by a comma is evaluated left-to-right
and the value of the left expression is discarded. All side effects
of the left expression are performed before the evaluation of the
right expression. The type and value of the result are the type and
value of the right operand; the result is an lvalue if its right
operand is.
2 In contexts where comma is given a special meaning, for example, in
lists of arguments to functions (_expr.call_) and lists of initializ
ers (_dcl.init_), the comma operator as described in this clause can
appear only in parentheses; for example,
f(a, (t=3, t+2), c);
has three arguments, the second of which has the value 5.
5.19 Constant expressions [expr.const]
1 In several places, C++ requires expressions that evaluate to an inte
gral constant: as array bounds (_dcl.array_), as case expressions
(_stmt.switch_), as bit-field lengths (_class.bit_), and as enumerator
initializers (_dcl.enum_).
constant-expression:
conditional-expression
An integral constant-expression can involve only literals
(_lex.literal_), enumerators, const values of integral types initial
ized with constant expressions (_dcl.init_), and sizeof expressions.
Floating constants (_lex.fcon_) must be cast to integral types. Only
type conversions to integral types may be used. In particular, except
in sizeof expressions, functions, class objects, pointers, or refer
ences cannot be used, and assignment, increment, decrement, function-
call, or comma operators cannot be used.
2 Other expressions are considered constant-expressions only for the
purpose of non-local static object initialization
(_basic.start.init_). Such constant expressions shall evaluate to one
of the following:
--a null pointer constant (_conv.ptr_),
--a null member pointer value (_conv.mem_),
--an arithmetic constant expression,
--an address constant,
--an address constant for an object type plus or minus an integral
constant expression, or
--a pointer to member constant expression.
3 An arithmetic constant expression shall have arithmetic type and shall
only have operands that are integer constants (_lex.icon_), floating
constants (_lex.fcon_), enumerators, character constants (_lex.ccon_)
and sizeof expressions (_expr.sizeof_). Casts operators in an arith
metic constant expression shall only convert arithmetic types to
arithmetic types, except as part of an operand to the sizeof operator.
4 An address constant is a pointer to an lvalue designating an object of
static storage duration or a function. The pointer shall be created
explicitly, using the unary & operator, or implicitly using an expres
sion of array (_conv.array_) or function (_conv.func_) type. The sub
scripting operator [] and the class member access . and -> operators,
the & and * unary operators, and pointer casts (except dynamic_casts,
_expr.dynamic.cast_) may be used in the creation of an address con
stant, but the value of an object shall not be accessed by the use of
these operators. Function calls cannot be used in an address constant
expression, even if the function is inline and has a reference return
type.
5 A pointer to member constant expression shall be created using the
unary & operator applied to a qualified-id operand (_expr.unary.op_).