______________________________________________________________________ 5 Expressions [expr] ______________________________________________________________________ 1 [Note: this clause defines the syntax, order of evaluation, and mean ing of expressions. An expression is a sequence of operators and operands that specifies a computation. An expression can result in a value and can cause side effects. 2 Operators can be overloaded, that is, given meaning when applied to expressions of class type (_class_) or enumeration type (_dcl.enum_). Uses of overloaded operators are transformed into function calls as described in _over.oper_. Overloaded 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_), and are not guaran teed for operands of type bool. --end note] 3 This clause defines the effects of operators when applied to types for which they have not been overloaded. Operator overloading shall not modify the rules for the built-in operators, that is, for operators applied to types for which they are defined by this Standard. How ever, these built-in operators participate in overload resolution; see _over.match.oper_. 4 Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previ ous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Fur thermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expres sion; otherwise the behavior is undefined. [Example: i = v[i++]; // the behavior is undefined i = 7,i++,i++; // `i' becomes 9 i = ++i + 1; // the behavior is undefined i = i + 1; // the value of 'i' is incremented --end example] 5 If during the evaluation of an expression, the result is not mathemat ically defined or not in the range of representable values for its type, the behavior is undefined, unless such an expression is a con stant expression (_expr.const_), in which case the program is ill- formed. +------- BEGIN BOX 1 -------+ Change: The sentence above was modified to indicate that a compile- time diagnostic is required if the expression is a constant expres sion; this follows a resolution adopted by ISO C to deal with a Defect Report. +------- END BOX 1 -------+ [Note: 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 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 anal ysis, the expression designates the object or function denoted by the reference, and the expression is an lvalue. 7 An expression designating an object is called an object-expression. 8 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 conversions are applied to convert the expres sion to an rvalue. [Note: because cv-qualifiers are removed from the type of an expression of non-class type when the expression is con verted to an rvalue, an lvalue expression of type const int can, for example, be used where an rvalue expression of type int is required. ] 9 Many 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, which are defined as follows: --If either operand is of type long double, the other shall be con verted to long double. --Otherwise, if either operand is double, the other shall be converted to double. --Otherwise, if either operand is float, the other shall be converted to float. --Otherwise, the integral promotions (_conv.prom_) shall be performed on both operands.1) --Then, if either operand is unsigned long the other shall be con verted to unsigned long. --Otherwise, if one operand is a long int and the other unsigned int, _________________________ 1) As a consequence, operands of type bool, wchar_t, or an enumerated type are converted to some integral type. then if a long int can represent all the values of an unsigned int, the unsigned int shall be converted to a long int; otherwise both operands shall be converted to unsigned long int. --Otherwise, if either operand is long, the other shall be converted to long. --Otherwise, if either operand is unsigned, the other shall be con verted to unsigned. [Note: otherwise, the only remaining case is that both operands are int ] 10The values of the floating operands and the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.2) 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 id-expression: unqualified-id qualified-id 2 A literal is a primary expression. Its type depends on its form (_lex.literal_). A string literal is an lvalue; all other literals are rvalues. 3 The keyword this names a pointer to the object for which a nonstatic member function (_class.this_) is invoked. The keyword this shall be used only inside a nonstatic class member function body (_class.mfct_) or in a constructor mem-initializer (_class.base.init_). 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, name, or operator-function-id is. The identifier, name, or operator-function-id shall have global namespace _________________________ 2) The cast and assignment operators must still perform their specific conversions as described in _expr.cast_, _expr.static.cast_ and _ex pr.ass_. scope. [Note: the use of :: allows a type, an object, a function, or an enumerator declared in the global namespace to be referred to even if its identifier has been hidden (_basic.lookup.qual_). ] 5 A parenthesized expression is a primary expression whose type and value are identical to those of the enclosed expression. The presence of parentheses does not affect whether the expression is an lvalue. 6 An id-expression is a restricted form of a primary-expression. [Note: an id-expression can appear after . and -> operators (_expr.ref_). ] id-expression: unqualified-id qualified-id unqualified-id: identifier operator-function-id conversion-function-id ~ class-name template-id 7 An identifier is an id-expression provided it has been suitably declared (_dcl.dcl_). [Note: for operator-function-ids, see _over.oper_; for conversion-function-ids, see _class.conv.fct_. A class-name prefixed by ~ denotes a destructor; see _class.dtor_. ] 8 qualified-id: nested-name-specifier templateopt unqualified-id nested-name-specifier: class-or-namespace-name :: nested-name-specifieropt class-or-namespace-name: class-name namespace-name A nested-name-specifier that names a class, optionally followed by the keyword template (_temp.arg.explicit_), and then followed by the name of a member of either that class (_class.mem_) or one of its base classes (_class.derived_), is a qualified-id; _class.qual_ describes name look up for class members that appear in qualified-ids. The type of the qualified-id is the type of the member. The result is the mem ber. The result is an lvalue if the member is. [Note: a class member can be used in a qualified-id as soon as the member's point of decla ration (_basic.scope.pdecl_) has been encountered in the class member- specification. ] Where class-name :: class-name is used, and the two class-names refer to the same class, this notation names the construc tor (_class.ctor_). Where class-name :: ~ class-name is used, the two class-names shall refer to the same class; this notation names the destructor (_class.dtor_). [Note: a typedef-name that names a class is a class-name (_dcl.typedef_). Except as the identifier in the declarator for a constructor or destructor definition outside of a class member-specification (_class.ctor_, _class.dtor_), a typedef- name that names a class may be used in a qualified-id to refer to a constructor or destructor. ] 9 A nested-name-specifier that names a namespace (_basic.namespace_), followed by the name of a member of that namespace is a qualified-id; _namespace.qual_ describes name look up for namespace members that appear in qualified-ids. The type of the qualified-id is the type of the member. The result is the member. The result is an lvalue if the member is. 10In 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. 11An id-expression that denotes a nonstatic data member or member func tion of a class can only be used: --as part of a class member access (_expr.ref_) in which the object- expression refers to the member's class or a class derived from that class, or --to form a pointer to member (_expr.unary.op_), or --in the body of a nonstatic member function of that class or of a class derived from that class (_class.mfct.nonstatic_), or --in a mem-initializer for a constructor for that class or for a class derived from that class (_class.base.init_). 12A template-id shall be used as an unqualified-id only as specified in clauses _temp.explicit_, _temp.spec_, and _temp.class.spec_. 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 . templateopt ::opt id-expression postfix-expression -> templateopt ::opt id-expression postfix-expression . pseudo-destructor-name postfix-expression -> pseudo-destructor-name 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 pseudo-destructor-name: ::opt nested-name-specifieropt type-name :: ~ type-name ::opt nested-name-specifieropt ~ type-name 5.2.1 Subscripting [expr.sub] 1 A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall have the type "pointer to T" and the other shall have enumeration or integral type. The result is an lvalue of type "T." The type "T" shall be a com pletely-defined object type.3) The expression E1[E2] is identical (by definition) to *((E1)+(E2)). [Note: 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 function4) (_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 an ordinary function call, the postfix expression shall be either an lvalue that refers to a function (in which case the func tion-to-pointer standard conversion (_conv.func_) is suppressed on the postfix expression), or it shall have pointer to function type. For a member function call, the postfix expression shall be an implicit (_class.mfct.nonstatic_, _class.static_) or explicit class member access (_expr.ref_) whose id-expression is a function member name, or a pointer-to-member expression (_expr.mptr.oper_) selecting a function member. The first expression in the postfix expression is then called the object expression, and the call is as a member of the object pointed to or referred to. In the case of an implicit class member access, the implied object is the one pointed to by this. [Note: a member function call of the form f() is interpreted as (*this).f() (see _class.mfct.nonstatic_). ] If a function or member function name is used, the name can be overloaded (_over_), in which case the appro priate function shall be selected according to the rules in _over.match_. The function called in a member function call is nor mally selected according to the static type of the object expression (see _class.derived_), but if that function is virtual the function actually called will be the final overrider (_class.virtual_) of the selected function in the dynamic type of the object expression [Note: the type of the object pointed or referred to by the current value of the object expression. Clause _class.cdtor_ describes the behavior of virtual function calls when the object-expression refers to an object under construction or destruction. ] _________________________ 3) This is true even if the subscript operator is used in the follow ing common idiom: &x[0]. 4) A static member function (_class.static_) is an ordinary function. 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 shall be a complete object type, a reference type or the type void. 3 When a function is called, each parameter (_dcl.fct_) shall be ini tialized (_dcl.init_, _class.copy_, _class.ctor_) with its correspond ing argument. When a function is called, the parameters that have object type shall have completely-defined object type. [Note: this still allows a parameter to be a pointer or reference to an incomplete class type. However, it prevents a passed-by-value parameter to have an incomplete class type. ] During the initialization of a parameter, an implementation may avoid the construction of extra temporaries by combining the conversions on the associated argument and/or the con struction of temporaries with the initialization of the parameter (see _class.temporary_). The lifetime of a parameter ends when the func tion in which it is defined returns. The initialization and destruc tion of each parameter occurs within the context of the calling func tion. [Example: the access of the constructor, conversion functions or destructor is checked at the point of call in the calling function. If a constructor or destructor for a function parameter throws an exception, the search for a handler starts in the scope of the calling function; in particular, if the function called has a function-try- block with a handler that could handle the exception, this handler is not considered. ] 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 over rider is converted to the return type of the statically chosen func tion. 4 [Note: a function can change the values of its non-const parameters, but these changes cannot affect the values of the arguments except where a parameter is of a non-const reference type (_dcl.ref_). Where a parameter is of reference type a temporary object is introduced if needed (_dcl.type_, _lex.literal_, _lex.string_, _dcl.array_, _class.temporary_). In addition, it is possible to modify the values of nonconstant objects through pointer parameters. 5 A function can 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_). ] 6 If no declaration of the called function is accessible from the scope of the call the program is ill-formed. [Note: this implies that, except where the ellipsis (...) is used, a parameter is available for each argument. ] 7 When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (_lib.support.runtime_). The lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the argument expression. After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed. If the argument has a non-POD class type (_class_), the behavior is undefined. If the argument has integral or enumeration type that is subject to the integral promo tions (_conv.prom_), or a floating point type that is subject to the floating point promotion (_conv.fpprom_), the value of the argument is converted to the promoted type before the call. These promotions are referred to as the default argument promotions. 8 The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified. 9 Recursive calls are permitted. 10A 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 simple- type-specifier specifies a class type, the class type shall be com plete. If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (_dcl.init_, _class.ctor_), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as an rvalue. 2 The expression T(), where T is a simple-type-specifier (_dcl.type.simple_), creates an rvalue of the specified type, whose value is determined by default-initialization (_dcl.init_). [Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting rvalue (_basic.lval_). ] 5.2.4 Pseudo destructor call [expr.pseudo] 1 The use of a pseudo-destructor-name after a dot . or arrow -> opera tor represents the destructor for the non-class type named by type- name. The result shall only be used as the operand for the function call operator (), and the result of such a call has type void. The only effect is the evaluation of the postfix-expression before the dot or arrow. 2 The left hand side of the dot operator shall be of scalar type. The left hand side of the arrow operator shall be of pointer to scalar type. This scalar type is the object type. The type designated by the pseudo-destructor-name shall be the same as the object type. Fur thermore, the two type-names in a pseudo-destructor-name of the form ::opt nested-name-specifieropt type-name :: ~ type-name shall designate the same scalar type. 5.2.5 Class member access [expr.ref] 1 A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template (_temp.arg.explicit_), and then fol lowed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow is evaluated;5) 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). In these cases, the id-expression shall name a member of the class. [Note: because the name of a class is inserted in its class scope (_class_), the name of a class is also considered a nested mem ber of that class. ] [Note: _basic.lookup.classref_ describes how names are looked up after the . and -> operators. ] 3 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)6). 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. cv represents an arbitrary set of cv-qualifiers, as defined in _basic.type.qualifier_. 4 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 T, then E1.E2 is an lvalue; the expression designates the named member of the class. The type of E1.E2 is 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 _________________________ 5) 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. 6) Note that if E1 has the type "pointer to class X", then (*(E1)) is an lvalue. 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 mem ber, 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) member function, function overload resolution (_over.match_) is used to determine whether E1.E2 refers to a static or a non-static member function. --If it refers to a 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 "function of (parameter type list) returning T". --Otherwise, if E1.E2 refers to a non-static member function, and the type of E2 is "function of (parameter type list) cv returning T", then E1.E2 is not an lvalue. The expression designates a non- static member function. 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 E1. The type of E1.E2 is "function of (parameter type list) cv returning T". --If E2 is a nested type, the expression E1.E2 is ill-formed. --If E2 is a member enumerator, and the type of E2 is T, the expres sion E1.E2 is not an lvalue. The type of E1.E2 is T. 5 [Note: "class objects" can be structures (_class.mem_) and unions (_class.union_). Classes are discussed in clause _class_. ] 5.2.6 Increment and decrement [expr.post.incr] 1 The value obtained by applying a postfix ++ is the value that the operand had before applying the operator. [Note: the value obtained is a copy of the original value ] The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic 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. [Note: this use is deprecated, see annex _depr_. ] The result is an rvalue. The type of the result is the cv-unqualified version of the type of the operand. 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.7 Dynamic cast [expr.dynamic.cast] 1 The result of the expression dynamic_cast<T>(v) is the result of con verting the expression v to type T. T shall be a pointer or reference to a complete class type, or "pointer to cv void". Types shall not be defined in a dynamic_cast. The dynamic_cast operator shall not cast away constness (_expr.const.cast_). 2 If T is a pointer type, v shall be an rvalue of a pointer to complete class type, and the result is an rvalue of type T. If T is a refer ence type, v shall be an lvalue of a complete class type, and the result is an lvalue of the type referred to by T. 3 If the type of v is the same as the required result type (which, for convenience, will be called R in this description), or it can be con verted to R via a qualification conversion (_conv.qual_) in the pointer case, the result is v (converted if necessary). 4 If the value of v is a null pointer value in the pointer case, the result is the null pointer value of type R. 5 If T is "pointer to cv1 B" and v has type "pointer to cv2 D" such that B is a 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 "reference to cv1 B" and v has type cv2 D" such that B is a base class of D, the result is an lvalue for the unique7) B sub-object of the D object referred to by v. In both the pointer and reference cases, cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2, and B shall be an accessible unambiguous base class of D. [Exam ple: struct B {}; struct D : B {}; void foo(D* dp) { B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp; } --end example] 6 Otherwise, v shall be a pointer to or an lvalue of a polymorphic type (_class.virtual_). 7 If T is "pointer to cv void," then the result is a pointer to the most derived object pointed to by v. Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be con verted to the type pointed or referred to by T. 8 The run-time check logically executes like this: If, in the most derived object pointed (referred) to by v, v points (refers) to a pub lic base class sub-object of a T object, and if only one object of type T is derived from the sub-object pointed (referred) to by v, the _________________________ 7) The most derived object (_intro.object_) pointed or referred to by v can contain other B objects as base classes, but these are ignored. result is a pointer (an lvalue referring) to that T object. Other wise, if the type of the most derived object has an unambiguous public base class of type T, the result is a pointer (reference) to the T sub-object of the most derived object. 9 Otherwise, the run-time check fails. 10The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws bad_cast (_lib.bad.cast_). [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; // succeeds: finds unique A D* dp = dynamic_cast<D*>(ap); // fails: yields 0 // f has two D sub-objects E* ep = (E*)ap; // ill-formed: // cast from virtual base E* ep1 = dynamic_cast<E*>(ap); // succeeds } --end example] [Note: Clause _class.cdtor_ describes the behavior of a dynamic_cast applied to an object under construction or destruction. ] 5.2.8 Type identification [expr.typeid] 1 The result of a typeid expression is an lvalue of type const std::type_info (_lib.type.info_). The lifetime of the object referred to by the lvalue extends to the end of the program. Whether or not the destructor is called for the type_info object at the end of the program is unspecified. 2 When typeid is applied to an lvalue expression whose type is a poly morphic class type (_class.virtual_), the result refers to a type_info object representing the type of the most derived object (_intro.object_) (that is, the dynamic type) to which the lvalue refers. If the lvalue expression is obtained by applying the unary * operator to a pointer8) and the pointer is a null pointer value _________________________ 8) If p is an expression of pointer type, then *p, (*p), *(p), ((*p)), (_conv.ptr_), the typeid expression throws the bad_typeid exception (_lib.bad.typeid_). 3 When typeid is applied to an expression other than an lvalue of a polymorphic class type, the result refers to a type_info object repre senting the static type of the expression. Lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to- pointer (_conv.func_) conversions are not applied to the expression. If the type of the expression is a class type, the class shall be com pletely-defined. The expression is not evaluated. 4 When typeid is applied to a type-id, the result refers to a type_info object representing the type of the type-id. If the type of the type- id is a reference type, the result of the typeid expression refers to a type_info object representing the referenced type. If the type of the type-id is a class type or a reference to a class type, the class shall be completely-defined. 5 The top-level cv-qualifiers of the lvalue expression or the type-id that is the operand of typeid are always ignored. [Example: class D { ... }; D d1; const D d2; typeid(d1) == typeid(d2); // yields true typeid(D) == typeid(const D); // yields true typeid(D) == typeid(d2); // yields true typeid(D) == typeid(const D&);// yields true --end example] 6 If the header <typeinfo> (_lib.type.info_) is not included prior to a use of typeid, the result of a typeid expression is an lvalue that has the incompletely-defined class type const std::type_info, and a pro gram that explicitly names this class type before inclusion of the header is ill-formed. 7 [Note: clause _class.cdtor_ describes the behavior of typeid applied to an object under construction or destruction. ] 5.2.9 Static cast [expr.static.cast] 1 The result of the expression static_cast<T>(v) is the result of con verting the expression v to type T. If T is a reference type, the result is an lvalue; otherwise, the result is an rvalue. T shall not be an incomplete class type, a pointer to an incomplete class type, or a reference to an incomplete class type. v shall not be a pointer to an incomplete class type, or an lvalue that has incomplete class type. Types shall not be defined in a static_cast. The static_cast operator shall not cast away constness (_expr.const.cast_). _________________________ *((p)), and so on all meet this requirement. 2 An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e);" is well-formed, for some invented temporary variable t (_dcl.init_). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary vari able as the result of the conversion. The result is an lvalue if T is a reference type (_dcl.ref_), and an rvalue otherwise. The expression e is used as an lvalue if and only if the declaration uses it as an lvalue. 3 Otherwise, the static_cast shall perform one of the conversions listed below. No other conversion shall be performed explicitly using a static_cast. 4 Any expression can be explicitly converted to type cv void." The expression value is discarded. 5 An lvalue of type cv1 B", where B is a class type, can be cast to type "reference to cv2 D", where D is a class derived (_class.derived_) from B, if a valid standard conversion from "pointer to cv2 D" to "pointer to cv2 B" exists (_conv.ptr_), cv2 is the same cv- qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D. The result is an lvalue of type cv2 D." If the lvalue of type cv1 B" is actually a sub-object of an object of type D, the lvalue refers to the enclosing object of type D. Other wise, the result of the cast is undefined. [Example: struct B {}; struct D : public B {}; D d; B &br = d; static_cast<D&>(br); // produces lvalue to the original d object --end example] 6 The inverse of any standard conversion sequence (_conv_), other than the lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), function-to-pointer (_conv.func_), base-class (_conv.class_), and boolean (_conv.bool_) conversions, can be performed explicitly using static_cast subject to the restriction that the explicit conversion does not cast away constness (_expr.const.cast_), and the following additional rules for specific cases: 7 A value of integral type can 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. 8 An rvalue of type "pointer to cv1 B", where B is a class type, can be converted to an rvalue of type "pointer to cv2 D", where D is a class derived (_class.derived_) from B, if a valid standard conversion from "pointer to cv2 D" to "pointer to cv2 B" exists (_conv.ptr_), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D and not a base class of a vir tual base class of D. The null pointer value (_conv.ptr_) is converted to the null pointer value of the destination type. If the rvalue of type "pointer to cv1 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 result of the cast is undefined. 9 An rvalue of type "pointer to member of D of type cv1 T" can be con verted to an rvalue of type "pointer to member of B of type cv2 T", where B is not a virtual base class (_class.derived_) of D and not a base class of a virtual base class of D, if a valid standard conver sion from "pointer to member of B of type cv2 T" to "pointer to member of D of type cv2 T" exists (_conv.mem_), and cv2 is the same cv- qualification as, or greater cv-qualification than, cv1. The null member pointer value (_conv.mem_) is converted to the null member pointer value of the destination type. If class B contains the origi nal member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the origi nal member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see _expr.mptr.oper_. ] 5.2.10 Reinterpret cast [expr.reinterpret.cast] 1 The result of the expression reinterpret_cast<T>(v) is the result of converting the expression v to type T. If T is a reference type, the result is an lvalue; otherwise, the result is an rvalue and, the lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the the expression v. Types shall not be defined in a reinter pret_cast. Conversions that can be performed explicitly using rein terpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast. 2 The reinterpret_cast operator shall not cast away constness. [Note: see _expr.const.cast_ for the definition of ``casting away const ness''. ] Any expression may be cast to its own type using a reinter pret_cast operator. 3 The mapping performed by reinterpret_cast is implementation-defined. [Note: it might, or might not, produce a representation different from the original value. ] 4 A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined [Note: it is intended to be unsurprising to those who know the addressing structure of the underlying machine. ] 5 A value of integral type or enumeration type can be explicitly con verted 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 A pointer to a function can 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 (_dcl.fct_) that is not the same as the type used in the definition of the function is undefined. Except that converting an rvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [Note: see also _conv.ptr_ for more details of pointer conversions. ] 7 A pointer to an object can be explicitly converted to a pointer to an object of different type.9) 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, the result of such a pointer conversion is unspecified. 8 The null pointer value (_conv.ptr_) is converted to the null pointer value of the destination type. 9 An rvalue of type "pointer to member of X of type T1" can be explic itly converted to an rvalue of type "pointer to member of Y of type T2" if T1 and T2 are both function types or both object types.10) The null member pointer value (_conv.mem_) is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases: --converting an rvalue of type "pointer to member function" to a dif ferent 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 alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer to member value. 10Calling a member function through a pointer to member that represents a function type (_dcl.fct_) that differs from the function type speci fied on the member function declaration results in undefined behavior, except when calling a virtual function whose function type differs from the function type of the pointer to member only as permitted by the rules for overriding virtual functions (_class.virtual_). 11An lvalue expression of type T1 can be cast to the type "reference to T2" if an expression of type "pointer to T1" can be explicitly _________________________ 9) The types may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness. 10) T1 and T2 may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness. converted to the type "pointer to T2" using a reinterpret_cast. That is, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators. The result is an lvalue that refers to the same object as the source lvalue, but with a different type. No temporary is cre ated, no copy is made, and constructors (_class.ctor_) or conversion functions (_class.conv_) are not called. 5.2.11 Const cast [expr.const.cast] 1 The result of the expression const_cast<T>(v) is of type T. If T is a reference type, the result is an lvalue; otherwise, the result is an rvalue and, the lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conver sions are performed on the expression v. Types shall not be defined in a const_cast. Conversions that can be performed explicitly using const_cast are listed below. No other conversion shall be performed explicitly using const_cast. 2 Any expression may be cast to its own type using a const_cast opera tor. 3 An rvalue of type "pointer to cv1 T" can be explicitly converted to the type "pointer to cv2 T", where T is any object type or the void type and, where cv1 and cv2 are cv-qualifications, using the cast const_cast<cv2 T*>. An lvalue of type cv1 T can be explicitly con verted to an lvalue of type cv2 T, where T is any object type and where cv1 and cv2 are cv-qualifications, using the cast const_cast<cv2 T&>. The result of a pointer or reference const_cast refers to the original object. 4 An rvalue of type "pointer to member of X of type cv1 T" can be explicitly converted to the type "pointer to member of X of type cv2 T", where T is a data member type and where cv1 and cv2 are cv- qualifiers, 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. 5 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. 6 [Note: 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 casts away a const-qualifier11) may produce undefined behavior (_dcl.type.cv_). ] _________________________ 11) const_cast is not limited to conversions that cast away a const- qualifier. 7 The following rules define the process known as casting away const ness. In these rules Tn and Xn represent types. For two pointer types: X1 is T1cv1,1 * ... cv1,N * where T1 is not a pointer type X2 is T2cv2,1 * ... cv2,M * where T2 is not a pointer type K is min(N,M) casting from X1 to X2 casts away constness if, for a non-pointer type T there does not exist an implicit conversion (_conv_) from: Tcv1,(N-K+1) * cv1,(N-K+2) * ... cv1,N * to Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M * 8 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. 9 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 constness if a cast from an rvalue of type "pointer to T1" to the type "pointer to T2" casts away constness. 10For multi-level pointer to members and multi-level mixed pointers and pointer to members (_conv.qual_), the "member" aspect of a pointer to member level is ignored when determining if a const cv-qualifier has been cast away. 11[Note: these rules are not intended to protect constness in all cases. For instance, conversions between pointers to functions are not cov ered because such conversions lead to values whose use causes unde fined behavior. For the same reasons, conversions between pointers 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. ] 5.3 Unary expressions [expr.unary] 1 Expressions with unary operators group right-to-left. unary-expression: postfix-expression ++ cast-expression -- cast-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 performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expres sion is "pointer to T," the type of the result is "T." [Note: a pointer to an incomplete type can be dereferenced. The lvalue thus obtained can be used in limited ways (to initialize a reference, for example); this lvalue must not be converted to an rvalue, see _conv.lval_. ] 2 The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. In the first case, 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 a qualified-id, if the member is a static member of type "T", the type of the result is plain "pointer to T." If the member is a nonstatic member of class C of type T, the type of the result is "pointer to member of class C of type T." [Example: struct A { int i; }; struct B : A { }; ... &B::i ... // has type "int A::*" --end example] [Note: a pointer to member formed from a mutable non static data member (_dcl.stc_) does not reflect the mutable specifier associated with the nonstatic data member. ] 3 A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type "pointer to mem ber." Neither does qualified-id, because there is no implicit conver sion from a qualified-id for a 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 &unqual ified-id a pointer to member, even within the scope of the unquali fied-id's class. ] 4 The address of an object of incomplete type can be taken, but if the complete type of that object is a class type that declares operator&() as a member function, then the behavior is undefined (and no diagnos tic is required). The operand of & shall not be a bit-field. 5 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: since the context might determine whether the operand is a static or nonstatic member func tion, the context can also affect whether the expression has type "pointer to function" or "pointer to member function." ] 6 The operand of the unary + operator shall have arithmetic, enumera tion, 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. 7 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. 8 The operand of the logical negation operator ! is implicitly con verted to bool (_conv_); its value is true if the converted operand is false and false otherwise. The type of the result is bool. 9 The operand of ~ shall 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. There is an ambiguity in the unary-expression ~X(), where X is a class-name. The ambiguity is resolved in favor of treating ~ as a unary complement rather than treating ~T as referring to a destructor. 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. [Note: see the discussions of addition (_expr.add_) and assignment operators (_expr.ass_) for infor mation on conversions. ] 2 The operand of prefix -- is modified by substracting 1. The operand shall not be of type bool. The requirements on the operand of prefix -- and the properties of its result are otherwise the same as those of prefix ++. 5.3.3 Sizeof [expr.sizeof] 1 The sizeof operator yields the number of bytes in the object represen tation of its operand. The operand is either an expression, which is not evaluated, or a parenthesized type-id. The sizeof operator shall not be applied to an expression that has function or incomplete type, or to an enumeration type before all its enumerators have been declared, or to the parenthesized name of such types, or to an lvalue that designates a bit-field. sizeof(char) is 1; the result of sizeof applied to any other fundamental type (_basic.fundamental_) is imple mentation-defined. [Note: in particular, sizeof(bool) and sizeof(wchar_t) are implementation-defined.12) ] [Note: See _intro.memory_ for the definition of byte and _basic.types_ for the definition of object representation. ] _________________________ 12) sizeof(bool) is not required to be 1. 2 When applied to a reference, the result is the size of the referenced type. When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array. The size of a most derived class shall be greater than zero (_intro.object_). 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 can be applied to a pointer to a function, but shall not be applied directly to a function. 4 The lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are not applied to the operand of sizeof. 5 Types shall not be defined in a sizeof expression. 6 The result is a constant of an implementation-defined type which is the same type as that which is named size_t in the standard header <cstddef>(_lib.support.types_). 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 nonabstract object type or array type (_intro.object_, _basic.types_, _class.abstract_). [Note: because, references are not objects, refer ences cannot be created by new-expressions. ] [Note: the type-id may be a cv-qualified type, in which case the object created by the new- expression has a cv-qualified type. ] 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: ptr-operator 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_). [Note: the lifetime of such an entity is not necessarily 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. If it is an array, the new-expression returns a pointer to the initial element of the array. 2 The new-type-id in a new-expression is the longest possible sequence of new-declarators. [Note: this prevents ambiguities between declara tor operators &, *, [], and their expression counterparts. ] [Exam ple: 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 Parentheses shall not appear in the new-type-id of a new-expression. 4 [Example: new int(*[10])(); // error is ill-formed because the binding is (new int) (*[10])(); // error Instead, the explicitly parenthesized version of the new operator can be used to create objects of compound types (_basic.compound_): 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 class declarations, or enu meration 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. [Note: both new int and new int[10] have type 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_) and evaluate to a strictly positive value. The expression in a direct-new-declarator shall have integral type (_basic.fundamental_) with a non-negative value. [Exam ple: 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, the allocation function is called to allocate an array with no ele ments. The pointer returned by the new-expression is 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 shall be the amount of space requested (which shall be no less than the size of the object being created and which may be greater than the size of the object being created only if the object is an array). 10An implementation shall provide default definitions for the global allocation functions operator new() for non-array types (_basic.stc.dynamic_, _lib.new.delete.single_) and operator new[]() for array types (_lib.new.delete.array_). [Note: A C++ program can provide alternative definitions of these functions (_lib.replacement.functions_), and/or class-specific versions (_class.free_). ] When the keyword new in a new-expression is pre ceeded by the unary :: operator, the global allocation function is used to allocate the storage. 11The new-placement syntax is used to supply additional arguments to an allocation function. If used, overload resolution is performed on a function call created by assembling an argument list consisting of the amount of space requested (the first argument) and the expressions in the new-placement part of the new-expression (the second and succeed ing arguments). The first of these arguments has type size_t and the remaining arguments have the correspoding types of the expressions in the new-placement. 12[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[](sizeof(T)*5+x), and --new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f). Here, x and y are non-negative, implementation-defined values repre senting array allocation overhead. Their value might vary from one invocation of new to another. ] 13The allocation function shall either return null or a pointer to a block of storage in which space for the object shall have been reserved. [Note: the block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. ] 14If the type of the object created by the new-expression is T: --If the new-initializer is omitted and T is a non-POD class type (_class_) (or array thereof), then if the default constructor for T is accessible it is called, otherwise the program is ill-formed; --If the new-initializer is omitted and T is a const-qualified type, if T is a class type with an explicitly-declared default construc tor, the default constructor for T is called, otherwise the new- expression is ill-formed; --If the new-initializer is omitted and T is a POD type (_basic.types_), then the object thus created has indeterminate value; --If the new-initializer is of the form (), default-initialization shall be performed (_dcl.init_); --If the new-initializer is of the form expression-list) and T is a class type, the appropriate constructor is called, using expression- list as the arguments (_dcl.init_); --If the new-initializer is of the form expression-list) and T is an arithmetic, enumeration, pointer, or pointer-to-member type and expression-list comprises exactly one expression, then the object is initialized to the (possibly converted) value of the expression (_dcl.init_); --Otherwise the new-expression is ill-formed. 15Access and ambiguity control are done for the allocation function, the deallocation function (_class.free_) and the constructor (_class.ctor_). 16The allocation function can indicate failure by throwing a bad_alloc exception (_except_, _lib.bad.alloc_). In this case no initialization is done. 17If the constructor exits using an exception and the new-expression does not contain a new-placement, then the deallocation function (_basic.stc.dynamic.deallocation_, _class.free_) is called 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. 18If the constructor exits using an exception and the new-expression contains a new-placement, a name lookup is performed on the name of operator delete in the scope of this new-expression. If the lookup succeeds and exactly one of the declarations found matches the decla ration of that placement operator new, then the matching placement operator delete shall be called (_basic.stc.dynamic.deallocation_). 19A declaration of placement operator delete matches the declaration of a placement operator new when it has the same number of parameters and all parameter types except the first are identical disregarding top- level cv-qualifiers. 20If placement operator delete is called, it is passed the same argu ments as were passed to placement operator new. If the implementation is allowed to make a copy of an argument as part of the placement new call, it is allowed to make a copy (of the same original value) as part of the placement delete call, or to reuse the copy made as part of the placement new call. If the copy is elided in one place, it need not be elided in the other. 21The 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. 22Whether the allocation function is called before evaluating the con structor arguments or after evaluating the constructor arguments but before entering the constructor is unspecified. It is also unspeci fied whether the arguments to a constructor are evaluated if the allo cation function returns the null pointer or exits using an exception. 5.3.5 Delete [expr.delete] 1 The delete-expression operator destroys a most derived object (_intro.object_) 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 operand shall have a pointer type, or a class type having a single conversion function (_class.conv.fct_) to a pointer type. 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, if the operand has a class type, the operand is converted to a pointer type by call ing the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section. 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, or a pointer to a sub-object (_intro.object_) repre senting a base class of such an object (_class.derived_). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of delete shall be a pointer to the first element of an array created by a new-expression. If not, the behavior is undefined. [Note: this means that the syntax of the delete-expression must match the type of the object allocated by new, not the syntax of the new-expression. ] [Note: a pointer to a const type can be the operand of a delete-expression. ] 3 In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.13) 4 The cast-expression in a delete-expression shall be evaluated exactly once. If the delete-expression calls the implementation deallocation function (_basic.stc.dynamic.deallocation_), and if the operand of the delete expression is not the null pointer constant, the deallocation function will deallocate the storage referenced by the pointer and render the pointer invalid. [Note: the value of a pointer that refers to deallocated storage is indeterminate. ] _________________________ 13) This implies that an object cannot be deleted using a pointer of type void* because there are no objects of type void. 5 If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined. 6 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; see _class.base.init_). 7 To free the storage pointed to, the delete-expression will call a deallocation function (_basic.stc.dynamic.deallocation_). 8 An implementation provides default definitions of the global dealloca tion functions operator delete() for non-arrays (_lib.new.delete.single_) and operator delete[]() for arrays (_lib.new.delete.array_). A C++ program can provide alternative defi nitions of these functions (_lib.replacement.functions_), and/or class-specific versions (_class.free_). When the keyword delete in a delete-expression is preceeded by the unary :: operator, the global deallocation function is used to deallocate the storage. 9 Access 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. The result is an lvalue if T is a reference type, otherwise the result is an rvalue. [Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting rvalue; see _basic.lval_. ] 2 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 3 Types shall not be defined in casts. 4 Any type conversion not mentioned below and not explicitly defined by the user (_class.conv_) is ill-formed. 5 The conversions performed by static_cast (_expr.static.cast_), rein terpret_cast (_expr.reinterpret.cast_), const_cast (_expr.const.cast_), or any sequence thereof, can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply. If a given conversion can be inter preted as a static_cast or reinterpret_cast, the static_cast interpre tation is used even if the resulting static_cast is ill-formed. [Example: struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; A *foo( D *p ) { return (A*)( p ); // ill-formed static_cast interpretation } --end example] 6 The operand of a cast using the cast notation can be an rvalue of type "pointer to incomplete class type". The destination type of a cast using the cast notation can be "pointer to incomplete class type". In such cases, even if there is a inheritance relationship between the source and destination classes, whether the the static_cast or rein terpret_cast interpretation is used is unspecified. 7 In addition to those conversions, the following static_cast and rein terpret_cast operations may be performed using the cast notation of explicit type conversion, even if the base class type is not accessi ble: --a pointer to an object of derived class type, an lvalue of derived class type, or a pointer to member of derived class type may be explicitly converted to a pointer to a base class type, a reference to a base class type, or a pointer to member of a base class type, respectively; --a pointer to an object of base class type, an lvalue of base class type, or a pointer to member of base class type may be explicitly converted to a pointer to a derived class type, a reference to a derived class type, or a pointer to member of a derived class type, respectively. 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 shall be of type "pointer to member of T" to its first operand, which shall 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 shall be of type "pointer to member of T" to its first operand, which shall be of type "pointer to T" or "pointer to a class of which T is an unambigu ous and accessible base class." The result is an object or a function of the type specified by the second operand. 4 If the dynamic type of the object does not contain the member to which the pointer refers, the behavior is undefined. 5 The restrictions on cv-qualification, and the manner in which the cv- qualifiers of the operands are combined to produce the cv-qualifiers of the result, are the same as the rules for E1.E2 given in _expr.ref_. [Note: it is not possible to use a pointer to member that refers to a mutable member to modify a const class object. For exam ple, struct S { mutable int i; }; const S cs; int S::* pm = &S::i; // pm refers to mutable member S::i cs.*pm = 88; // ill-formed: cs is a const class ] 6 If the result of .* or ->* is a function, then that result can be used only as the operand for the function call operator (). [Example: (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 behavior 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 / shall have arithmetic or enumeration type; the operands of % shall have integral or enumeration type. The usual arithmetic conversions 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 behavior 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-defined. 5.7 Additive operators [expr.add] 1 The additive operators + and - group left-to-right. The usual arith metic conversions are performed for operands of arithmetic type. additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression For addition, either both operands shall have arithmetic or enumera tion type, or one operand shall be a pointer to a completely defined object type and the other shall have integral or enumeration type. 2 For subtraction, one of the following shall hold: --both operands have arithmetic or enumeration type; --both operands are pointers to cv-qualified or cv-unqualified ver sions 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 or enumeration 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, or the pointer operand points to the element of an array and the result points one past the last element of the same array. 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.support.types_). 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.14) 8 If the value 0 is added to or subtracted from a pointer value, the result compares equal to the original pointer value. If two pointers point to the same object or function or both point one past the end of the same array or both are null, and the two pointers are subtracted, the result compares equal to the value 0 converted to the type ptrdiff_t. 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 _________________________ 14) Another way to approach pointer arithmetic is first to convert the pointer(s) to character pointer(s): In this scheme the integral value of the expression 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 charac ter pointers is similarly divided by the size of the object originally pointed to. 7 When viewed in this way, an implementation need only provide one extra byte (which might overlap another object in the program) just after the end of the object in order to satisfy the "one past the last ele ment" requirements. The operands shall be of integral or enumeration type and integral promotions are performed. The type of the result is that of the pro moted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the pro moted left operand. 2 The value of E1 << E2 is E1 (interpreted as a bit pattern) left- shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 multiplied by the quan tity 2 raised to the power E2, reduced modulo ULONG_MAX+1 if E1 has type unsigned long, UINT_MAX+1 otherwise. [Note: the constants ULONG_MAX and UINT_MAX are defined in the header <climits>). ] 3 The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation- defined. 5.9 Relational operators [expr.rel] 1 The relational operators group left-to-right. [Example: 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 shall have arithmetic, enumeration 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 operands of arith metic or enumeration type. Pointer conversions are performed on pointer operands to bring them to the same type, which shall be a cv- qualified or cv-unqualified version of the type of one of the operands. [Note: this implies that any pointer can be compared to a null pointer constant and that any object pointer can be compared to a pointer of cv-qualified or cv-unqualified type void* (in the latter case the pointer is first implicitly converted to void*). ] Pointers to objects or functions of the same type (after pointer conversions) can be compared, with a result defined as follows: --If two pointers p and q 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, then p<=q and p>=q both yield true and p<q and p>q both yield false. --If two pointers p and q of the same type point to different objects or functions, or only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified. --If two pointers point to nonstatic data members of the same object, the pointer to the later declared member compares greater provided the two members are not separated by an access-specifier label (_class.access.spec_) and provided their class is not a union. --If two pointers point to nonstatic data members of the same object separated by an access-specifier label (_class.access.spec_) the result is unspecified. +------- BEGIN BOX 2 -------+ Should it at least be required to be consistent across all objects of the same type within the execution of a single program? +------- END BOX 2 -------+ --If two pointers point to data members of the same union object, 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 compares higher. --Other pointer comparisons are unspecified. 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. [Note: a<b == c<d is true whenever a<b and c<d have the same truth- value. ] 2 In addition, pointers to members can be compared. Pointer to member conversions (_conv.mem_) are performed to bring them to the same type, which shall be a cv-qualified or cv-unqualified version of the type of one of the operands. [Note: this implies that any pointer to member can be compared to an integral constant expression evaluating to zero. ] If both operands are null, they compare equal. Otherwise if only one is null, they compare unequal. Otherwise if either is a pointer to a virtual member function, the result is unspecified. Otherwise they compare equal if and only if they would refer to the same member of the same most derived object (_intro.object_) or the same subobject if they were dereferenced with a hypothetical object of the associated class type. [Example: struct B { int f(); }; struct L : B { }; struct R : B { }; struct D : L, R { }; int (B::*pb)() = &B::f; int (L::*pl)() = pb; int (R::*pr)() = pb; int (D::*pdl)() = pl; int (D::*pdr)() = pr; bool x = (pdl == pdr); // false --end example] 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 or enumeration 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 or enumeration 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 bit wise inclusive function of its operands. The operator applies only to integral or enumeration 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 implic itly converted to type bool (_conv_). The result is true if both operands are true and false otherwise. Unlike &, && guarantees left- to-right evaluation: 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 implic itly converted to bool (_conv_). 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 implicitly converted to bool (_conv_). 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. Only one of the second and third expressions is evaluated. 2 If either the second or the third operand has type (possibly cv- qualified) void, then the lvalue-to-rvalue (_conv.lval_), array-to- pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the second and third operands, and one of the following shall hold: --The second or the third operand (but not both) is a throw-expression (_except.throw_); the result is of the type of the other and is an rvalue. --Both the second and the third operands have type void; the result is of type void and is an rvalue. [Note: this includes the case where both operands are throw-expressions. ] 3 Otherwise, if either the second or the third operand has (possibly cv- qualified) class or enumeration type, overload resolution is used to determine the conversions (if any) to be applied to the operands (_over.match.oper_, _over.built_). The conversions thus determined are applied, and the converted operands are used in place of the orig inal operands for the remainder of this section. 4 If the second and third operands are lvalues and have the same type, the result is of that type and is an lvalue. 5 Otherwise, the result is an rvalue. Lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the second and third operands. After those conversions, one of the following shall hold: --The second and third operands have the same type; the result is of that type. --The second and third operands have arithmetic or enumeration type; the usual arithmetic conversions are performed to bring them to a common type, and the result is of that type. --The second and third operands have pointer type, or one has pointer type and the other is a null pointer constant; pointer conversions (_conv.ptr_) and qualification conversions (_conv.qual_) are per formed to bring them to a common type, whose cv-qualification shall match the cv-qualification of either the second or the third operand. The result is of the common type. --The second and third operands have pointer to member type, or one has pointer to member type and the other is a null pointer constant; pointer to member conversions (_conv.mem_) and qualification conver sions (_conv.qual_) are performed to bring them to a common type, whose cv-qualification shall match the cv-qualification of either the second or the third operand. The result is of the common type. 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 logical-or-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 implicitly converted (_conv_) to the cv-unqualified type of the left operand. 4 If the left operand is of class type, the class shall be complete. Assignment to objects of a class (_class_) X is defined by the func tion X::operator=() (_over.ass_). Unless X::operator=() is explicitly declared in the class member-specification, the implicitly-declared default assignment operator 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_). 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. In += and -=, E1 shall either have arithmetic or enumeration type or be a pointer to a possibly cv-qualified completely defined object type. In all other cases, E1 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 (_intro.execution_) of the left expression, except for the destruction of temporaries (_class.temporary_), are performed before the evalua tion 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, [Example: in lists of arguments to functions (_expr.call_) and lists of initializers (_dcl.init_) ] the comma operator as described in this clause can appear only in parentheses. [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 or enumeration constant: as array bounds (_dcl.array_, _expr.new_), as case expressions (_stmt.switch_), as bit-field lengths (_class.bit_), as enumerator initializers (_dcl.enum_), as static mem ber initializers (_class.static.data_), and as integral non-type tem plate arguments (_temp.arg_). constant-expression: conditional-expression An integral constant-expression can involve only literals (_lex.literal_), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (_dcl.init_), and sizeof expressions. Floating literals (_lex.fcon_) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not 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 value (_conv.ptr_), --a null member pointer value (_conv.mem_), --an arithmetic constant expression, --an address constant expression, --a reference constant expression, --an address constant expression 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 or enumeration type and shall only have operands that are integer literals (_lex.icon_), floating literals (_lex.fcon_), enumerators, character literals (_lex.ccon_) and sizeof expressions (_expr.sizeof_). Cast operators in an arithmetic constant expression shall only convert arithmetic or enumeration types to arithmetic or enumeration types, except as part of an operand to the sizeof operator. 4 An address constant expression is a pointer to an lvalue designating an object of static storage duration, a string literal (_lex.string_), or a function. The pointer shall be created explicitly, using the unary & operator, or implicitly using an expression of array (_conv.array_) or function (_conv.func_) type. The subscripting oper ator [] and the class member access . and -> operators, the & and * unary operators, and pointer casts (except dynamic_casts, _expr.dynamic.cast_) can be used in the creation of an address con stant expression, but the value of an object shall not be accessed by the use of these operators. An expression that designates the address of a member or base class of a non-POD class object (_class_) is not an address constant expression (_class.cdtor_). Function calls shall not be used in an address constant expression, even if the function is inline and has a reference return type. 5 A reference constant expression is an lvalue designating an object of static storage duration or a function. The subscripting operator [], the class member access . and -> operators, the & and * unary opera tors, and reference casts (except those invoking user-defined conver sion functions (_class.conv.fct_) and except dynamic_casts (_expr.dynamic.cast_)) can be used in the creation of a reference con stant expression, but the value of an object shall not be accessed by the use of these operators An lvalue expression that designates a mem ber or base class of a non-POD class object (_class_) is not a refer ence constant expression (_class.cdtor_). Function calls shall not be used in a reference constant expression, even if the function is inline and has a reference return type. 6 A pointer to member constant expression shall be created using the unary & operator applied to a qualified-id operand (_expr.unary.op_).