Postfix expressions group left-to-right.
postfix-expression: primary-expression postfix-expression [ expression ] postfix-expression [ braced-init-list ] postfix-expression ( expression-listopt ) simple-type-specifier ( expression-listopt ) typename-specifier ( expression-listopt ) simple-type-specifier braced-init-list typename-specifier braced-init-list 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: initializer-list
pseudo-destructor-name: nested-name-specifieropt type-name :: ~ type-name nested-name-specifier template simple-template-id :: ~ type-name nested-name-specifieropt ~ type-name ~ decltype-specifier
[ Note: The > token following the type-id in a dynamic_cast, static_cast, reinterpret_cast, or const_cast may be the product of replacing a >> token by two consecutive > tokens ([temp.names]). — end note ]
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 unscoped enumeration or integral type. The result is an lvalue of type “T.” The type “T” shall be a completely-defined object type.62 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. — end note ]
A braced-init-list shall not be used with the built-in subscript operator.
This is true even if the subscript operator is used in the following common idiom: &x[0].
There are two kinds of function call: ordinary function call and member function63 ([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 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.non-static], [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 call is as a member of the class object referred to by the object expression. 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.non-static]). — end note ] 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]. If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider ([class.virtual]) in the dynamic type of the object expression is called. [ Note: the dynamic type is the type of the object 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. — end note ]
[ Note: If a function or member function name is used, and name lookup ([basic.lookup]) does not find a declaration of that name, the program is ill-formed. No function is implicitly declared by such a call. — end note ]
If the postfix-expression designates a destructor ([class.dtor]), the type of the function call expression is void; otherwise, 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 an object type, a reference type or the type void.
When a function is called, each parameter ([dcl.fct]) shall be initialized ([dcl.init], [class.copy], [class.ctor]) with its corresponding argument. [ Note: Such initializations are indeterminately sequenced with respect to each other ([intro.execution]) — end note ] If the function is a non-static member function, the this parameter of the function ([class.this]) shall be initialized with a pointer to the object of the call, converted as if by an explicit type conversion ([expr.cast]). [ Note: There is no access or ambiguity checking on this conversion; the access checking and disambiguation are done as part of the (possibly implicit) class member access operator. See [class.member.lookup], [class.access.base], and [expr.ref]. — end note ] 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. — end note ] 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. — end example ] 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.
[ 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. — end note ]
A function can be declared to accept fewer arguments (by declaring default arguments ([dcl.fct.default])) or more arguments (by using the ellipsis, ..., or a function parameter pack ([dcl.fct])) than the number of parameters in the function definition ([dcl.fct.def]). [ Note: this implies that, except where the ellipsis (...) or a function parameter pack is used, a parameter is available for each argument. — end note ]
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 ([support.runtime]). [ Note: This paragraph does not apply to arguments passed to a function parameter pack. Function parameter packs are expanded during template instantiation ([temp.variadic]), thus each such argument has a corresponding parameter when a function template specialization is actually called. — end note ] 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. An argument that has (possibly cv-qualified) type std::nullptr_t is converted to type void* ([conv.ptr]). After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed. Passing a potentially-evaluated argument of class type (Clause [class]) having a non-trivial copy constructor, a non-trivial move constructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics. 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.
[ Note: The evaluations of the postfix expression and of the argument expressions are all unsequenced relative to one another. All side effects of argument expression evaluations are sequenced before the function is entered (see [intro.execution]). — end note ]
Recursive calls are permitted, except to the function named main ([basic.start.main]).
A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
If a function call is a prvalue of object type:
if the function call is either
the operand of a decltype-specifier or
the right operand of a comma operator that is the operand of a decltype-specifier,
a temporary object is not introduced for the prvalue. The type of the prvalue may be incomplete. [ Note: as a result, storage is not allocated for the prvalue and it is not destroyed; thus, a class type is not instantiated as a result of being the type of a function call in this context. This is true regardless of whether the expression uses function call notation or operator notation ([over.match.oper]). — end note ] [ Note: unlike the rule for a decltype-specifier that considers whether an id-expression is parenthesized ([dcl.type.simple]), parentheses have no special meaning in this context. — end note ]
otherwise, the type of the prvalue shall be complete.
A static member function ([class.static]) is an ordinary function.
A simple-type-specifier ([dcl.type.simple]) or typename-specifier ([temp.res]) 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 type specified is 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 a prvalue.
The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type,which is value-initialized ([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 prvalue ([basic.lval]). — end note ]
Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized ([dcl.init.list]) with the specified braced-init-list, and its value is that temporary object as a prvalue.
The use of a pseudo-destructor-name after a dot . or arrow -> operator represents the destructor for the non-class type denoted by type-name or decltype-specifier. 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.
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 cv-unqualified versions of the object type and of the type designated by the pseudo-destructor-name shall be the same type. Furthermore, the two type-names in a pseudo-destructor-name of the form
nested-name-specifieropt type-name :: ~ type-name
shall designate the same scalar type.
A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template ([temp.names]), and then followed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow is evaluated;64 the result of that evaluation, together with the id-expression, determines the result of the entire postfix expression.
For the first option (dot) the first expression shall have complete class type. For the second option (arrow) the first expression shall have pointer to complete class type. The expression E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder of [expr.ref] will address only the first option (dot).65 In either case, 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. — end note ] [ Note: [basic.lookup.classref] describes how names are looked up after the . and -> operators. — end note ]
Abbreviating postfix-expression.id-expression as E1.E2, E1 is called the object expression. The type and value category of E1.E2 are determined as follows. In the remainder of [expr.ref], cq represents either const or the absence of const and vq represents either volatile or the absence of volatile. cv represents an arbitrary set of cv-qualifiers, as defined in [basic.type.qualifier].
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 E1 is an lvalue, then E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue; otherwise, it is a prvalue. Let the notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.
If E2 is a (possibly overloaded) 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 ref-qualifieropt returning T”, then E1.E2 is a prvalue. 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]). [ Note: Any redundant set of parentheses surrounding the expression is ignored ([expr.prim]). — end note ] 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 expression E1.E2 is a prvalue. The type of E1.E2 is T.
If E2 is a non-static data member or a non-static member function, the program is ill-formed if the class of which E2 is directly a member is an ambiguous base ([class.member.lookup]) of the naming class ([class.access.base]) of E2. [ Note: The program is also ill-formed if the naming class is an ambiguous base of the class type of the object expression; see [class.access.base]. — end note ]
If the class member access expression is evaluated, the subexpression 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.
Note that (*(E1)) is an lvalue.
The value of a postfix ++ expression is the value of its operand. [ Note: the value obtained is a copy of the original value — end note ] 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. The value of the operand 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]. — end note ] The value computation of the ++ expression is sequenced before the modification of the operand object. With respect to an indeterminately-sequenced function call, the operation of postfix ++ is a single evaluation. [ Note: Therefore, a function call shall not intervene between the lvalue-to-rvalue conversion and the side effect associated with any single postfix ++ operator. — end note ] The result is a prvalue. The type of the result is the cv-unqualified version of the type of the operand. See also [expr.add] and [expr.ass].
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]. — end note ]
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.” The dynamic_cast operator shall not cast away constness ([expr.const.cast]).
If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of type T. If T is an lvalue 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. If T is an rvalue reference type, v shall be an expression having a complete class type, and the result is an xvalue of the type referred to by T.
If the type of v is the same as T, or it is the same as T except that the class object type in T is more cv-qualified than the class object type in v, the result is v (converted if necessary).
If the value of v is a null pointer value in the pointer case, the result is the null pointer value of type T.
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 subobject 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 the unique B subobject of the D object referred to by v. 66 The result is an lvalue if T is an lvalue reference, or an xvalue if T is an rvalue reference. In both the pointer and reference cases, the program is ill-formed if cv2 has greater cv-qualification than cv1 or if B is an inaccessible or ambiguous 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;
}
— end example ]
Otherwise, v shall be a pointer to or an lvalue of a polymorphic type ([class.virtual]).
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.
If C is the class type to which T points or refers, the run-time check logically executes as follows:
If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class subobject of a C object, and if only one object of type C is derived from the subobject pointed (referred) to by v the result points (refers) to that C object.
Otherwise, if v points (refers) to a public base class subobject of the most derived object, and the type of the most derived object has a base class, of type C, that is unambiguous and public, the result points (refers) to the C subobject of the most derived object.
Otherwise, the run-time check fails.
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 std::bad_cast ([bad.cast]).
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); // ill-formed (not a run-time check) } 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 subobjects E* ep = (E*)ap; // ill-formed: cast from virtual base E* ep1 = dynamic_cast<E*>(ap); // succeeds }
— end example ] [ Note: [class.cdtor] describes the behavior of a dynamic_cast applied to an object under construction or destruction. — end note ]
The most derived object ([intro.object]) pointed or referred to by v can contain other B objects as base classes, but these are ignored.
The result of a typeid expression is an lvalue of static type const std::type_info ([type.info]) and dynamic type const std::type_info or const name where name is an implementation-defined class publicly derived from std :: type_info which preserves the behavior described in [type.info].67 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 std::type_info object at the end of the program is unspecified.
When typeid is applied to a glvalue expression whose type is a polymorphic class type ([class.virtual]), the result refers to a std::type_info object representing the type of the most derived object ([intro.object]) (that is, the dynamic type) to which the glvalue refers. If the glvalue expression is obtained by applying the unary * operator to a pointer68 and the pointer is a null pointer value ([conv.ptr]), the typeid expression throws the std::bad_typeid exception ([bad.typeid]).
When typeid is applied to an expression other than a glvalue of a polymorphic class type, the result refers to a std::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 an unevaluated operand (Clause [expr]).
When typeid is applied to a type-id, the result refers to a std::type_info object representing the type of the type-id. If the type of the type-id is a reference to a possibly cv-qualified type, the result of the typeid expression refers to a std::type_info object representing the cv-unqualified 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.
The top-level cv-qualifiers of the glvalue 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 ]
If the header <typeinfo> ([type.info]) is not included prior to a use of typeid, the program is ill-formed.
[ Note: [class.cdtor] describes the behavior of typeid applied to an object under construction or destruction. — end note ]
The recommended name for such a class is extended_type_info.
If p is an expression of pointer type, then *p, (*p), *(p), ((*p)), *((p)), and so on all meet this requirement.
The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue. The static_cast operator shall not cast away constness ([expr.const.cast]).
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 neither a virtual base class of D nor a base class of a virtual base class of D. The result has type “cv2 D.” An xvalue of type “cv1 B” may be cast to type “rvalue reference to cv2 D” with the same constraints as for an lvalue of type “cv1 B.” If the object of type “cv1 B” is actually a subobject of an object of type D, the result 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
— end example ]
A glvalue of type “cv1 T1” can be cast to type “rvalue reference to cv2 T2” if “cv2 T2” is reference-compatible with “cv1 T1” ([dcl.init.ref]). The result refers to the object or the specified base class subobject thereof. If T2 is an inaccessible (Clause [class.access]) or ambiguous ([class.member.lookup]) base class of T1, a program that necessitates such a cast is ill-formed.
Otherwise, 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 expression e is used as a glvalue if and only if the initialization uses it as a glvalue.
Otherwise, the static_cast shall perform one of the conversions listed below. No other conversion shall be performed explicitly using a static_cast.
Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression (Clause [expr]). [ Note: however, if the value is in a temporary object ([class.temporary]), the destructor for that object is not executed until the usual time, and the value of the object is preserved for the purpose of executing the destructor. — end note ]
The inverse of any standard conversion sequence (Clause [conv]) not containing an lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), function-to-pointer ([conv.func]), null pointer ([conv.ptr]), null member pointer ([conv.mem]), or boolean ([conv.bool]) conversion, can be performed explicitly using static_cast. A program is ill-formed if it uses static_cast to perform the inverse of an ill-formed standard conversion sequence. [ Example:
struct B { }; struct D : private B { }; void f() { static_cast<D*>((B*)0); // Error: B is a private base of D. static_cast<int B::*>((int D::*)0); // Error: B is a private base of D. }
— end example ]
The lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) conversions are applied to the operand. Such a static_cast is subject to the restriction that the explicit conversion does not cast away constness ([expr.const.cast]), and the following additional rules for specific cases:
A value of a scoped enumeration type ([dcl.enum]) can be explicitly converted to an integral type. The value is unchanged if the original value can be represented by the specified type. Otherwise, the resulting value is unspecified. A value of a scoped enumeration type can also be explicitly converted to a floating-point type; the result is the same as that of converting from the original value to the floating-point type.
A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values ([dcl.enum]). Otherwise, the resulting value is unspecified (and might not be in that range). A value of floating-point type can also be converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration ([conv.fpint]), and subsequently to the enumeration type.
A prvalue of type “pointer to cv1 B,” where B is a class type, can be converted to a prvalue 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 neither a virtual base class of D nor a base class of 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 prvalue of type “pointer to cv1 B” points to a B that is actually a subobject 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.
A prvalue of type “pointer to member of D of type cv1 T” can be converted to a prvalue 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.69 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]. — end note ]
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T,” where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. The null pointer value is converted to the null pointer value of the destination type. A value of type pointer to object converted to “pointer to cv void” and back, possibly with different cv-qualification, shall have its original value. [ Example:
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.
— end example ]
The result of the expression reinterpret_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue 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. Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.
The reinterpret_cast operator shall not cast away constness ([expr.const.cast]). An expression of integral, enumeration, pointer, or pointer-to-member type can be explicitly converted to its own type; such a cast yields the value of its operand.
[ Note: The mapping performed by reinterpret_cast might, or might not, produce a representation different from the original value. — end note ]
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. — end note ] A value of type std::nullptr_t can be converted to an integral type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type. [ Note: A reinterpret_cast cannot be used to convert a value of any type to the type std::nullptr_t. — end note ]
A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. [ Note: Except as described in [basic.stc.dynamic.safety], the result of such a conversion will not be a safely-derived pointer value. — end note ]
A function pointer can be explicitly converted to a function pointer 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 a prvalue 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. — end note ]
An object pointer can be explicitly converted to an object pointer of a different type.70 When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types ([basic.types]) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue 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 any other such pointer conversion is unspecified.
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning of such a conversion is implementation-defined, except that if an implementation supports conversions in both directions, converting a prvalue of one type to the other type and back, possibly with different cv-qualification, shall yield the original pointer value.
The null pointer value ([conv.ptr]) is converted to the null pointer value of the destination type. [ Note: A null pointer constant of type std::nullptr_t cannot be converted to a pointer type, and a null pointer constant of integral type is not necessarily converted to a null pointer value. — end note ]
A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types.71 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 a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.
converting a prvalue 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.
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 (and similarly for reinterpret_cast<T&&>(x)). The result refers to the same object as the source lvalue, but with a different type. The result is an lvalue for an lvalue reference type or an rvalue reference to function type and an xvalue for an rvalue reference to object type. No temporary is created, no copy is made, and constructors ([class.ctor]) or conversion functions ([class.conv]) are not called.72
The types may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness.
T1 and T2 may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness.
The result of the expression const_cast<T>(v) is of type T. If T is an lvalue reference to object type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue 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. Conversions that can be performed explicitly using const_cast are listed below. No other conversion shall be performed explicitly using const_cast.
[ Note: Subject to the restrictions in this section, an expression may be cast to its own type using a const_cast operator. — end note ]
For two pointer types T1 and T2 where
and
where T is any object type or the void type and where cv1,k and cv2,k may be different cv-qualifications, a prvalue 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.
For two object types T1 and T2, if a pointer to T1 can be explicitly converted to the type “pointer to T2” using a const_cast, then the following conversions can also be made:
an lvalue of type T1 can be explicitly converted to an lvalue of type T2 using the cast const_cast<T2&>;
a glvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>; and
if T1 is a class type, a prvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>.
The result of a reference const_cast refers to the original object.
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.
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.
[ 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-qualifier73 may produce undefined behavior ([dcl.type.cv]). — end note ]
The following rules define the process known as casting away constness. In these rules Tn and Xn represent types. For two pointer types:
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:
to
Casting from an lvalue of type T1 to an lvalue of type T2 using an lvalue reference cast or casting from an expression of type T1 to an xvalue of type T2 using an rvalue reference cast casts away constness if a cast from a prvalue of type “pointer to T1” to the type “pointer to T2” casts away constness.
Casting from a prvalue 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 a prvalue of type “pointer to T1” to the type “pointer to T2” casts away constness.
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.
[ 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. — end note ]
const_cast is not limited to conversions that cast away a const-qualifier.