-1- [Note: Clause expr 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 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 (clause 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 clause expr,
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 guaranteed for operands of type
bool.
--- end note]
-3- Clause expr 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. However, these built-in operators participate in overload resolution, and as part of that process user-defined conversions will be considered where necessary to convert the operands to types appropriate for the built-in operator. If a built-in operator is selected, such conversions will be applied to the operands before the operation is considered further according to the rules in clause expr; see over.match.oper, over.built.
-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.*
[Footnote: The precedence of operators is not directly specified, but it can be derived from the syntax. --- end foonote]Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, 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 expression; otherwise the behavior is undefined. [Example:
i = v[i++]; //the behavior is unspecified i = 7, i++, i++; // i becomes 9 i = ++i + 1; // the behavior is unspecified i = i + 1; // the value of i is incremented
-5- If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined, unless such an expression is a constant expression (expr.const), in which case the program is ill-formed. [Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, 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 analysis, 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 expression to an rvalue. [Note: because cv-qualifiers are removed from the type of an expression of non-class type when the expression is converted 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 or enumeration 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:
[Footnote: As a consequence, operands of type bool, wchar_t, or an enumerated type are converted to some integral type. --- end foonote]
-10- The 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.*
[Footnote: The cast and assignment operators must still perform their specific conversions as described in expr.cast, expr.static.cast and expr.ass. --- end foonote]
-1- Primary expressions are literals, names, and names qualified by the scope resolution operator ::.
primary-expression: literal this ( expression ) id-expression id-expression: unqualified-id qualified-id unqualified-id: identifier operator-function-id conversion-function-id ~ class-name template-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). The type of the expression is a pointer to the function's class (class.this), possibly with cv-qualifiers on the class type. The expression is an rvalue.
-4- The operator :: followed by an identifier, a qualified-id, or an operator-function-id is a primary-expression. Its type is specified by the declaration of the identifier, qualified-id, or operator-function-id. The result is the entity denoted by the identifier, qualified-id, or operator-function-id. The result is an lvalue if the entity is a function or variable. The identifier, qualified-id, or operator-function-id shall have global namespace scope or be visible in global scope because of a using-directive (namespace.udir). [Note: the use of :: allows a type, an object, a function, an enumerator, or a namespace 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. The parenthesized expression can be used in exactly the same contexts as those where the enclosed expression can be used, and with the same meaning, except as otherwise indicated.
-6- An id-expression is a restricted form of a primary-expression. [Note: an id-expression can appear after . and -> operators (expr.ref). ]
-7- An identifier is an id-expression provided it has been suitably declared (clause dcl.dcl). [Note: for operator-function-ids, see over.oper; for conversion-function-ids, see class.conv.fct; for template-ids, see temp.names. A class-name prefixed by ~ denotes a destructor; see class.dtor. Within the definition of a nonstatic member function, an identifier that names a nonstatic member is transformed to a class member access expression (class.mfct.nonstatic). ] The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member.
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 (clause class.derived), is a qualified-id; class.qual describes name lookup for class members that appear in qualified-ids. The result is the member. The type of the result is the type of the member. The result is an lvalue if the member is a static member function or a data member. [Note: a class member can be referred to using a qualified-id at any point in its potential scope (basic.scope.class). ] 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 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. ]qualified-id: ::opt nested-name-specifier templateopt unqualified-id :: identifier :: operator-function-id :: template-id nested-name-specifier: class-or-namespace-name :: nested-name-specifieropt class-or-namespace-name :: template nested-name-specifier class-or-namespace-name: class-name namespace-name
-8- A nested-name-specifier that names a namespace (basic.namespace), followed by the name of a member of that namespace (or the name of a member of a namespace made visible by a using-directive ) is a qualified-id; namespace.qual describes name lookup for namespace members that appear in qualified-ids. The result is the member. The type of the result is the type of the member. The result is an lvalue if the member is a function or a variable.
-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.
-10- An id-expression that denotes a nonstatic data member or nonstatic member function of a class can only be used:
-11-
A
template-id
shall be used as an
unqualified-id
only as specified in 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 ) typename ::opt nested-name-specifier identifier ( expression-listopt ) typename ::opt nested-name-specifier templateopt template-id ( expression-listopt ) postfix-expression . templateopt id-expression postfix-expression -> templateopt 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-specifier template template-id :: ~ type-name ::opt nested-name-specifieropt ~ type-name
-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 completely-defined object type.*
[Footnote: This is true even if the subscript operator is used in the following common idiom: &x[0]. --- end foonote]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. ]
-1- There are two kinds of function call: ordinary function call and member function* (class.mfct) call.
[Footnote: A static member function (class.static) is an ordinary function. --- end foonote]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 function-to-pointer standard conversion (conv.func) is suppressed on the postfix expression), or it shall have pointer to function type. Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function's definition is undefined (dcl.link). 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 (clause over), in which case the appropriate function shall 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 (clause class.derived), but if that function is virtual and is not specified using a qualified-id then 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 dynamic type is the type of the object pointed or referred to by the current value of the object expression. class.cdtor describes the behavior of virtual function calls when the object-expression refers to an object under construction or destruction. ]
-2- If no declaration of the called function is visible from the scope of the call the program is ill-formed.
-3- 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.
-4- When a function is called, each parameter (dcl.fct) shall be initialized (dcl.init, class.copy, class.ctor) with its corresponding 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 construction of temporaries with the initialization of the parameter (see class.temporary). The lifetime of a parameter ends when the function in which it is defined returns. The initialization and destruction of each parameter occurs within the context of the calling function. [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 (clause except) 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 overrider is converted to the return type of the statically chosen function.
-5- [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 reference type (dcl.ref); if the reference is to a const-qualified type, const_cast is required to be used to cast away the constness in order to modify the argument's value. Where a parameter is of const 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. ]
-6- 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 function definition (dcl.fct.def). [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 (clause class), the behavior is undefined. If the argument has integral or enumeration type that is subject to the integral promotions (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, except to the function named main (basic.start.main).
-10-
A function call is an lvalue if and only if the result type is a reference.
5.2.3 - Explicit type conversion (functional notation) [expr.type.conv]
-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 is a single expression, the type conversion 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 complete. 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)
for a non-array complete object type or the (possibly cv-qualified) void type,
creates an rvalue of the specified type,
whose value is determined by
default-initialization (dcl.init; no initialization is done for the
void()
case).
[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 -> operator 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. Furthermore, the two type-names in a pseudo-destructor-name of the form
shall designate the same scalar type. The cv-unqualified versions of the object type and of the type designated by the pseudo-destructor-name shall be the same type.::opt nested-name-specifieropt type-name :: ~ type-name
-1- A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template (temp.arg.explicit), and then followed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow is evaluated;*
[Footnote: This evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member. --- end foonote]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 or of one of its base classes. [Note: because the name of a class is inserted in its class scope (clause class), the name of a class is also considered a nested member 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 expr.ref will address only the first option (dot)*.
[Footnote: Note that if E1 has the type ``pointer to class X'', then (*(E1)) is an lvalue. --- end foonote]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 expr.ref, 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.
-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 a complete 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.
[Note:
For prefix increment and decrement, see expr.pre.incr.
]
5.2.7 - Dynamic cast [expr.dynamic.cast]
-1- The result of the expression dynamic_cast<T>(v) is the result of converting 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 reference 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 is the same as R except that the class object type in R is more cv-qualified than the class object type in v, 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 unique* B sub-object of the D object referred to by v.
[Footnote: The most derived object (intro.object) pointed or referred to by v can contain other B objects as base classes, but these are ignored. --- end foonote]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. [Example:
struct B {}; struct D : B {}; void foo(D* dp) { B* bp = dynamic_cast<B*>(dp); //equivalent to B* bp = dp; }
-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 converted to the type pointed or referred to by T.
-8- The run-time check logically executes as follows:
-9-
The 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); // fails ap = dynamic_cast<A*>(bp); // fails bp = dynamic_cast<B*>(ap); // fails ap = dynamic_cast<A*>(&d); // succeeds bp = dynamic_cast<B*>(&d); // 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 }
-1- The result of a typeid expression is an lvalue of static type const std::type_info (lib.type.info) and dynamic type const std::type_info or const name where name is an implementation-defined class derived from std::type_info which preserves the behavior described in lib.type.info.*
[Footnote: The recommended name for such a class is extended_type_info. --- end foonote]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 polymorphic 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 pointer*
[Footnote: If p is an expression of pointer type, then *p, (*p), *(p), ((*p)), *((p)), and so on all meet this requirement. --- end foonote]and the pointer is a null pointer value (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 representing 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 completely-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. Types shall not be defined in the type-id.
-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
-6- If the header <typeinfo> (lib.type.info) is not included prior to a use of typeid, the program is ill-formed.
-7-
[Note:
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 converting the expression v to type T. If T is a reference type, the result is an lvalue; otherwise, the result is an rvalue. Types shall not be defined in a static_cast. The static_cast operator shall not cast away constness (expr.const.cast).
-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 variable 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 initialization 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. [Note: however, if the value is in a temporary variable (class.temporary), the destructor for that variable is not executed until the usual time, and the value of the variable is preserved for the purpose of executing the destructor. ] The lvalue-to-rvalue (conv.lval), array-to-pointer (conv.array), and function-to-pointer (conv.func) standard conversions are not applied to the expression.
-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 (clause class.derived) from B, if a valid standard conversion from ``pointer to D'' to ``pointer to 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. Otherwise, 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
-6- The inverse of any standard conversion sequence (clause conv), other than the lvalue-to-rvalue (conv.lval), array-to-pointer (conv.array), function-to-pointer (conv.func), 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 (clause class.derived) from B, if a valid standard conversion from ``pointer to D'' to ``pointer to 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 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 converted to an rvalue of type ``pointer to member of B of type cv2 T'', where B is a base class (clause class.derived) of D, if a valid standard conversion from ``pointer to member of B of type T'' to ``pointer to member of D of type T'' exists (conv.mem), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.*
[Footnote: Function types (including those used in pointer to member function types) are never cv-qualified; see dcl.fct . --- end foonote]The null member pointer value (conv.mem) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original 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. ]
-10-
An rvalue of type ``pointer to cv void'' can be explicitly
converted to a pointer to object type.
A value of type pointer to object
converted to ``pointer to cv void'' and back to
the original pointer type will have its original value.
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 reinterpret_cast. Conversions that can be performed explicitly using reinterpret_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 constness''. Subject to the restrictions in this section, an expression may be cast to its own type using a reinterpret_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 converted to a pointer.*
[Footnote: Converting an integral constant expression (expr.const) with value zero always yields a null pointer (conv.ptr), but converting other expressions that happen to have value zero need not yield a null pointer. --- end foonote]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.*
[Footnote: The types may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness. --- end foonote]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 explicitly 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.*
[Footnote: T1 and T2 may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness. --- end foonote]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:
-10- An 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 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 created, no copy is made, and constructors (class.ctor) or conversion functions (class.conv) are not called.*
[Footnote: This is sometimes referred to as a type pun. --- end foonote]
-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 conversions 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- [Note: Subject to the restrictions in this section, an expression may be cast to its own type using a const_cast operator. ]
-3-
For two pointer types T1 and T2 where
T1~roman is~cv sub 1,0~roman "pointer to"~cv sub 1,1~roman "pointer to"~...~cv sub 1,n-1~roman "pointer to"~cv sub 1,n~Tand
T2~roman is~cv sub 2,0~roman "pointer to"~cv sub 2,1~roman "pointer to"~...~cv sub 2,n-1~roman "pointer to"~cv sub 2,n~Twhere T is any object type or the void type and where cv1,k and cv2,k may be different cv-qualifications, an rvalue of type T1 may be explicitly converted to the type T2 using a const_cast. The result of a pointer const_cast refers to the original object.
-4- An lvalue of type T1 can be explicitly converted to an lvalue of type T2 using the cast const_cast<T2&> (where T1 and T2 are object types) if a pointer to T1 can be explicitly converted to the type pointer to T2 using a const_cast. The result of a reference const_cast refers to the original object.
-5- For a const_cast involving pointers to data members, multi-level pointers to data members and multi-level mixed pointers and pointers to data members (conv.qual), the rules for const_cast are the same as those used for pointers; the ``member'' aspect of a pointer to member is ignored when determining where the cv-qualifiers are added or removed by the const_cast. The result of a pointer to data member const_cast refers to the same member as the original (uncast) pointer to data member.
-6- 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 destination type.
-7- [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-qualifier* may produce undefined behavior (dcl.type.cv).
[Footnote: const_cast is not limited to conversions that cast away a const-qualifier. --- end foonote]]
-8- The following rules define the process known as casting away constness. In these rules Tn and Xn represent types. For two pointer types:
font CW X1~roman is~ font CW T1 cv sub 1,1~*~...~cv sub 1,N~*~~~roman {where~T1~is~not~a~pointer~"type"}
font CW X2~roman is~ font CW T2 cv sub 2,1~*~...~cv sub 2,M~*~~~roman {where~T2~is~not~a~pointer~"type"}
K~roman 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 (clause conv) from:
T cv sub 1,(N-K+1)~*~cv sub 1,(N-K+2)~*~...~cv sub 1,N~*to
T cv sub 2,(M-K+1)~*~cv sub 2,(M-K+2)~*~...~cv sub 2,M~*
-9- Casting from an lvalue of type T1 to an lvalue of type T2 using a reference cast casts away constness if a cast from an rvalue of type ``pointer to T1'' to the type ``pointer to T2'' casts away constness.
-10- 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.
-11- For 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.
-12-
[Note:
some conversions which involve only changes in cv-qualification cannot
be done using
const_cast.
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 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 * & + - ! ~
-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 expression is ``pointer to T,'' the type of the result is ``T.'' [Note: a pointer to an incomplete type (other than cv void ) 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::*
-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 member.'' Neither does qualified-id, because there is no implicit conversion 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 &unqualified-id a pointer to member, even within the scope of the unqualified-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 diagnostic is required). The operand of & shall not be a bit-field.
-5- The address of an overloaded function (clause over) can be taken only in a context that uniquely determines which version of the overloaded function is referred to (see over.over). [Note: since the context might determine whether the operand is a static or nonstatic member function, 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, 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.
-7- The operand of the unary - operator shall have arithmetic or enumeration type and the result is the negation of its operand. Integral promotion is performed on integral or enumeration operands. The negative 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 converted to bool (clause 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 performed.
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
~X
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 information on conversions. ]
-2-
The operand of prefix
--
is modified by subtracting
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
++.
[Note:
For postfix increment and decrement, see expr.post.incr.
]
5.3.3 - Sizeof [expr.sizeof]
-1- The sizeof operator yields the number of bytes in the object representation 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), sizeof(signed char) and sizeof(unsigned char) are 1; the result of sizeof applied to any other fundamental type (basic.fundamental) is implementation-defined. [Note: in particular, sizeof(bool) and sizeof(wchar_t) are implementation-defined.*
[Footnote: sizeof(bool) is not required to be 1. --- end foonote]] [Note: See intro.memory for the definition of byte and basic.types for the definition of object representation. ]
-2- When applied to a reference or a reference type, 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). The result of applying sizeof to a base class subobject is the size of the base class type.*
[Footnote: The actual size of a base class subobject may be less than the result of applying sizeof to the subobject, due to virtual base classes and less strict padding requirements on base class subobjects. --- end foonote]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 type
size_t.
[Note:
size_t
is defined
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) or new-type-id to which it is applied. The type of that object is the allocated type. This type shall be a complete object type, but not an abstract class type or array thereof (intro.object, basic.types, class.abstract). [Note: because references are not objects, references 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 ]
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 a non-array 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.new-initializer: ( expression-listopt )
-2- The new-type-id in a new-expression is the longest possible sequence of new-declarators. [Note: this prevents ambiguities between declarator operators &, *, [], and their expression counterparts. ] [Example:
The * is the pointer declarator and not the multiplication operator. ]new int * i; //syntax error: parsed as (new int*) i // not as (new int)*i
-3- [Note: parentheses in a new-type-id of a new-expression can have surprising effects. [Example:
is ill-formed because the binding isnew 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])(); //error
allocates an array of 10 pointers to functions (taking no argument and returning int). ] ]new (int (*[10])());
-4- The type-specifier-seq shall not contain class declarations, or enumeration declarations.
-5- 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 element (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]. ]
-6- Every constant-expression in a direct-new-declarator shall be an integral 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. [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 undefined. ]
-7- When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements. The pointer returned by the new-expression is non-null. [Note: If the library allocation function is called, the pointer returned is distinct from the pointer to any other object. ]
-8- A new-expression obtains storage for the object by calling an allocation function (basic.stc.dynamic.allocation). If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function (basic.stc.dynamic.deallocation). If the allocated type is a non-array type, the allocation function's name is operator new and the deallocation function's name is operator delete. If the allocated type is an array type, the allocation function's name is operator new[] and the deallocation function's name is operator delete[]. [Note: an implementation shall provide default definitions for the global allocation functions (basic.stc.dynamic, lib.new.delete.single, lib.new.delete.array). A C++ program can provide alternative definitions of these functions (lib.replacement.functions) and/or class-specific versions (class.free). ]
-9- If the new-expression begins with a unary :: operator, the allocation function's name is looked up in the global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function's name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type, the allocation function's name is looked up in the global scope.
-10- A new-expression passes the amount of space requested to the allocation function as the first argument of type std::size_t. That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array. For arrays of char and unsigned char, the difference between the result of the new-expression and the address returned by the allocation function shall be an integral multiple of the most stringent alignment requirement (basic.types) of any object type whose size is no greater than the size of the array being created. [Note: Because allocation functions are assumed to return pointers to storage that is appropriately aligned for objects of any type, this constraint on array allocation overhead permits the common idiom of allocating character arrays into which objects of other types will later be placed. ]
-11- The 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 succeeding arguments). The first of these arguments has type size_t and the remaining arguments have the corresponding types of the expressions in the new-placement.
-12- [Example:
-13- [Note: unless an allocation function is declared with an empty exception-specification (except.spec), throw(), it indicates failure to allocate storage by throwing a bad_alloc exception (clause except, lib.bad.alloc); it returns a non-null pointer otherwise. If the allocation function is declared with an empty exception-specification, throw(), it returns null to indicate failure to allocate storage and a non-null pointer otherwise. ] If the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null.
-14- [Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. 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. ]
-15- A new-expression that creates an object of type T initializes that object as follows:
-16- If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function (class.free), and the constructor (class.ctor). If the new expression creates an array of objects of class type, access and ambiguity control are done for the destructor (class.dtor).
-17- If any part of the object initialization described above*
[Footnote: This may include evaluating a new-initializer and/or calling a constructor. --- end foonote]terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function 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. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object's memory to be freed. [Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]
-18- If the new-expression begins with a unary :: operator, the deallocation function's name is looked up in the global scope. Otherwise, if the allocated type is a class type T or an array thereof, the deallocation function's name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type or array thereof, the deallocation function's name is looked up in the global scope.
-19-
A declaration of a placement deallocation function matches the
declaration of a placement allocation function if it has the same
number of parameters and, after parameter transformations (dcl.fct),
all parameter types except the first are identical.
Any non-placement
deallocation function matches a non-placement allocation function.
If
the lookup finds a single matching deallocation function, that function
will be called; otherwise, no deallocation function will be called.
-1-
The
delete-expression
operator destroys a most derived object (intro.object) or array created by a
new-expression.
-2-
If the operand has a class type, the operand is converted
to a pointer type by calling the above-mentioned conversion function, and
the converted operand is used in place of the original operand for the
remainder of this section.
In either alternative, if the value of the operand of
delete
is the null pointer the operation has no effect.
In the first alternative (delete object), the value
of the operand of
delete
shall be a pointer to a non-array object
or a pointer to a sub-object (intro.object)
representing a base class of such an object (clause class.derived).
If not, the behavior is undefined.
In the second alternative (delete array), the value of the operand of
delete
shall be the pointer value which resulted from a previous array
new-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.*
-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
thus rendering the pointer invalid.
[Note:
the value of a pointer that refers to deallocated storage is indeterminate.
]
-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 the completion of their constructor; see class.base.init).
-7-
The
delete-expression
will call a deallocation function (basic.stc.dynamic.deallocation).
-8-
[Note:
An implementation provides default definitions of the global
deallocation 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 definitions
of these functions (lib.replacement.functions),
and/or class-specific versions (class.free).
]
When the keyword
delete
in a
delete-expression
is preceded 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
function and the destructor (class.dtor, class.free).
-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.
-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
-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
static_cast
or
reinterpret_cast
interpretation is used is unspecified.
-7-
In addition to
those conversions,
the following
static_cast
and
reinterpret_cast
operations
(optionally followed by a
const_cast
operation)
may be performed using the cast notation of explicit type conversion,
even if the base class type is not accessible:
-1-
The pointer-to-member operators
->*
and
.*
group left-to-right.
-2-
The binary operator
.*
binds its second operand, which shall be of type ``pointer to member of
T''
(where
T
is a completely-defined class type)
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''
(where
T
is a completely-defined class type)
to its first operand, which shall 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 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 example,
-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:
-1-
The multiplicative operators
*,
/,
and
%
group left-to-right.
-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 undefined; 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*.
-1-
The additive operators
+
and
-
group left-to-right.
The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.
-2-
For subtraction,
one of the following shall hold:
-3-
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.
-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 elements.
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 expressions
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 expression
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.*
-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 element'' requirements.
--- end foonote] -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.
-1-
The shift operators
<<
and
>>
group left-to-right.
-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 quantity 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.
-1-
The relational operators group left-to-right.
[Example:
a<b<c
means
(a<b)<c
and
not
(a<b)&&(b<c).
]
-2-
The usual arithmetic conversions are performed on
operands of arithmetic or enumeration type.
Pointer conversions (conv.ptr) and qualification conversions (conv.qual)
are performed on pointer operands
(or on a pointer operand and a null pointer constant)
to bring them to their
composite pointer type.
If one operand is a null pointer constant, the composite pointer type is the
type of the other operand.
Otherwise, if one of the operands has type
``pointer to
cv1
void'',
then the other has type ``pointer to
cv2
T''
and the composite pointer type is ``pointer to
cv12
void'',
where
cv12
is the union of
cv1
and
cv2.
Otherwise, the composite pointer type is a pointer type
similar (conv.qual) to the type of one of the operands, with a cv-qualification
signature (conv.qual) that is the union of the cv-qualification signatures of the
operand types.
[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 to (possibly cv-qualified)
void.
]
[Example:
-1-
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.
]
Pointers to objects or functions of the same type (after pointer
conversions) can be compared for equality.
Two pointers of the same type compare equal if and only if they are both null,
both point to the same object or function,
or both point one past the end of the same array.
-2-
In addition, pointers to members can be compared, or a pointer to member
and a null pointer constant.
Pointer to member conversions (conv.mem) and qualification
conversions (conv.qual) are performed to bring them to
a common type.
If one operand is a null pointer
constant, the common type is the type of the other operand.
Otherwise, the
common type is a pointer to member type similar (conv.qual) to the type of one
of the operands, with a cv-qualification signature (conv.qual) that is the
union of the cv-qualification signatures of the operand types.
[Note:
this implies that any pointer to member can be compared to
a null pointer constant.
]
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:
-1-
The usual arithmetic conversions are performed;
the result is the bitwise
AND
function of the operands.
The operator applies only to integral or enumeration
operands.
-1-
The usual arithmetic conversions are performed;
the result is the bitwise exclusive
OR
function of the operands.
The operator applies only to integral
or enumeration operands.
-1-
The usual arithmetic conversions are performed;
the result is the bitwise inclusive
OR
function of its operands.
The operator applies only to integral
or enumeration operands.
-1-
The
&&
operator groups left-to-right.
The operands are both implicitly converted to type
bool
(clause 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.
-1-
The
||
operator groups left-to-right.
The operands are both implicitly converted to
bool
(clause 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.
-1-
Conditional expressions group right-to-left.
The first expression is implicitly converted to
bool
(clause 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:
-3-
Otherwise, if the second and third operand have different types, and
either has (possibly cv-qualified) class type, an attempt is made to
convert each of those operands to the type of the other.
The process
for determining whether an operand expression
E1
of type
T1
can be converted to match an operand expression
E2
of type
T2
is defined as follows:
Using this process, it is determined whether the second operand can be
converted to match the third operand, and whether the third operand can be
converted to match the second operand.
If both can be converted, or one
can be converted but the conversion is ambiguous, the program is ill-formed.
If neither can be converted, the operands are left unchanged and further
checking is performed as described below.
If exactly one conversion
is possible, that conversion is applied to the chosen operand and
the converted operand is used in place of the original operand 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.
If the second and third operand
do not have the same type, and either has (possibly cv-qualified)
class type, overload resolution is used to determine the conversions
(if any) to be applied to the operands (over.match.oper, over.built).
If the overload resolution fails, the program is ill-formed.
Otherwise, the conversions thus determined are applied, and the
converted operands are used in place of the original operands for
the remainder of this section.
-6-
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:
-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.
-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 (clause 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 is defined by the copy assignment operator
(class.copy, over.ass).
-5-
[Note:
For class objects, assignment is not in general the same as initialization
(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 reference.
-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 type or be a pointer to a
possibly cv-qualified completely defined object type.
In all other cases,
E1
shall have arithmetic type.
-8-
If the value being stored in an object is accessed from another object
that overlaps in any way the storage of the first object,
then the overlap shall be exact and the two objects shall have the same type,
otherwise the behavior is undefined.
-1-
The comma operator groups left-to-right.
-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 clause expr
can appear only in parentheses.
[Example:
-1-
In several places, C++ requires expressions that evaluate to
an integral 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 member initializers (class.static.data),
and as integral or enumeration non-type template arguments (temp.arg).
-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:
-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 a non-type template parameter of pointer type,
or using an expression of array (conv.array) or
function (conv.func) type.
The subscripting operator
[]
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 constant expression, but the
value of an object shall not be accessed by the use of these
operators.
If the subscripting operator is used, one of its operands shall be an
integral constant expression.
An expression that designates the address of a member or base
class of a non-POD class object (clause 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,
a non-type template parameter of reference type,
or a function.
The subscripting operator
[],
the class member access
.
and
->
operators, the
&
and
*
unary operators, and reference casts
(except those invoking user-defined conversion functions (class.conv.fct)
and except
dynamic_casts
(expr.dynamic.cast))
can be used in the creation of a reference constant expression,
but the value of an object shall not be accessed by the use of these operators.
If the subscripting operator is used, one of its operands shall be an
integral constant expression.
An lvalue expression that designates a member or base class of a non-POD class
object (clause class) is not a reference 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),
optionally preceded by a pointer to member cast (expr.static.cast).
5.3.5 - Delete [expr.delete]
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.
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
[Footnote:
For non-zero-length arrays, this is the same as a pointer to the
first element of the array created by that
new-expression.
Zero-length arrays do not have a first element.
--- end foonote]
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;
it is not necessary to cast away the constness (expr.const.cast) of the
pointer expression before it is used as the operand of the
delete-expression.
]
[Footnote:
This implies that an object cannot be deleted using a pointer of type
void*
because there are no objects of type
void.
--- end foonote]
5.4 - Explicit type conversion (cast notation) [expr.cast]
cast-expression:
unary-expression
( type-id ) cast-expression
can be performed using the cast notation of explicit type conversion.
The same semantic restrictions and behaviors apply.
If a conversion can be interpreted in more than one of the ways
listed above, the interpretation that appears first in the list
is used, even if a cast resulting from that interpretation is
ill-formed.
If a conversion can be interpreted in more than one way as a
static_cast
followed by a
const_cast,
the conversion 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]
5.5 - Pointer-to-member operators [expr.mptr.oper]
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression
]
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 object
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.
(ptr_to_obj->*ptr_to_mfct)(10);
5.6 - Multiplicative operators [expr.mul]
multiplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
[Footnote:
According to work underway toward the revision of ISO C,
the preferred algorithm for integer division follows the rules
defined in the ISO Fortran standard, ISO/IEC 1539:1991,
in which the quotient is always rounded toward zero.
--- end foonote]
5.7 - Additive operators [expr.add]
For addition, either both operands shall have
arithmetic or enumeration type, or one
operand shall be a pointer to a completely defined object type and the
other shall have integral or enumeration type.
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
[Footnote:
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
character pointers is similarly divided by the size of the object
originally pointed to.
5.8 - Shift operators [expr.shift]
The operands shall be of integral
or enumeration type and integral promotions are performed.
The type of the result is that of the promoted left operand.
The behavior is undefined if the right operand is negative,
or greater than or equal to the length in bits of the promoted left operand.
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
5.9 - Relational operators [expr.rel]
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.
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
void *p;
const int *q;
int **pi;
const int *const *pci;
void ct()
{
p <= q; //
Both converted to const void * before comparison
pi <= pci; // Both converted to const int *const * before comparison
}
--- end example]
Pointers to objects or functions of the same type (after pointer
conversions) can be compared,
with a result defined as follows:
5.10 - Equality operators [expr.eq]
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
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]
and-expression:
equality-expression
and-expression & equality-expression
5.12 - Bitwise exclusive OR operator [expr.xor]
exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
5.13 - Bitwise inclusive OR operator [expr.or]
inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression
5.14 - Logical AND operator [expr.log.and]
logical-and-expression:
inclusive-or-expression
logical-and-expression && inclusive-or-expression
5.15 - Logical OR operator [expr.log.or]
logical-or-expression:
logical-and-expression
logical-or-expression || logical-and-expression
5.16 - Conditional operator [expr.cond]
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
5.17 - Assignment operators [expr.ass]
assignment-expression:
conditional-expression
logical-or-expression assignment-operator assignment-expression
throw-expression
assignment-operator: one of
= *= /= %= += -= >>= <<= &= ^= |=
5.18 - Comma operator [expr.comma]
A pair of expressions separated by a comma is evaluated
left-to-right and the value of the left expression is
discarded.
The lvalue-to-rvalue (conv.lval), array-to-pointer (conv.array),
and function-to-pointer (conv.func) standard conversions are not applied
to the left expression.
All side effects (intro.execution) of the left expression,
except for the destruction of temporaries (class.temporary),
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.
expression:
assignment-expression
expression , assignment-expression
has three arguments, the second of which has the value
5.
]
f(a, (t=3, t+2), c);
5.19 - Constant expressions [expr.const]
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),
non-type template parameters of integral or enumeration types,
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.
constant-expression:
conditional-expression