Полезная информация


  ______________________________________________________________________

  5   Expressions                                                 [expr]

  ______________________________________________________________________

1 [Note: this clause defines the syntax, order of evaluation, and  mean-
  ing  of  expressions.   An  expression  is a sequence of operators and
  operands that specifies a computation.  An expression can result in  a
  value and can cause side effects.

2 Operators  can  be  overloaded, that is, given meaning when applied to
  expressions of class type (_class_) or enumeration type  (_dcl.enum_).
  Uses  of  overloaded  operators are transformed into function calls as
  described in _over.oper_.  Overloaded operators  obey  the  rules  for
  syntax specified in this clause, but the requirements of operand type,
  lvalue, and evaluation order are replaced by the  rules  for  function
  call.   Relations between operators, such as ++a meaning a+=1, are not
  guaranteed for overloaded operators (_over.oper_), and are not guaran-
  teed for operands of type bool.   --end note]

3 This clause defines the effects of operators when applied to types for
  which they have not been overloaded.  Operator overloading  shall  not
  modify  the  rules  for the built-in operators, that is, for operators
  applied to types for which they are defined by  this  Standard.   How-
  ever, these built-in operators participate in overload resolution; see
  _over.match.oper_.

4 Except where noted, the order of evaluation of operands of  individual
  operators  and subexpressions of individual expressions, and the order
  in which side effects take place, is unspecified.  Between the  previ-
  ous  and  next  sequence  point  a scalar object shall have its stored
  value modified at most once by the evaluation of an expression.   Fur-
  thermore,  the  prior  value  shall  be accessed only to determine the
  value to be stored.  The requirements of this paragraph shall  be  met
  for  each  allowable  ordering of the subexpressions of a full expres-
  sion; otherwise the behavior is undefined.  [Example:
          i = v[i++];      // the behavior is undefined
          i = 7, i++, i++; // `i' becomes 9

          i = ++i + 1;     // the behavior is undefined
          i = i + 1;       // the value of 'i' is incremented
   --end example]

5 If during the evaluation of an expression, the result is not mathemat-
  ically  defined  or  not  in the range of representable values for its
  type, the behavior is undefined, unless such an expression is  a  con-
  stant  expression  (_expr.const_),  in  which case the program is ill-
  formed.  [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 anal-
  ysis,  the expression designates the object or function denoted by the
  reference, and the expression is an lvalue.

7 An expression designating an object is called an object-expression.

8 Whenever an lvalue expression appears as an  operand  of  an  operator
  that   expects  an  rvalue  for  that  operand,  the  lvalue-to-rvalue
  (_conv.lval_), array-to-pointer (_conv.array_), or function-to-pointer
  (_conv.func_)  standard conversions are applied to convert the expres-
  sion to an rvalue.  [Note: because cv-qualifiers are removed from  the
  type  of  an  expression of non-class type when the expression is con-
  verted to an rvalue, an lvalue expression of type const int  can,  for
  example,  be  used where an rvalue expression of type int is required.
  ]

9 Many binary operators that expect operands of arithmetic  or  enumera-
  tion  type  cause conversions and yield result types in a similar way.
  The purpose is to yield a common type, which is also the type  of  the
  result.   This  pattern  is  called  the usual arithmetic conversions,
  which are defined as follows:

  --If either operand is of type long double, the other  shall  be  con-
    verted to long double.

  --Otherwise, if either operand is double, the other shall be converted
    to double.

  --Otherwise, if either operand is float, the other shall be  converted
    to float.

  --Otherwise,  the integral promotions (_conv.prom_) shall be performed
    on both operands.1)

  --Then,  if  either  operand  is unsigned long the other shall be con-
    verted to unsigned long.

  --Otherwise, if one operand is a long int and the other unsigned  int,
    then  if a long int can represent all the values of an unsigned int,
    the unsigned int shall be converted to a long  int;  otherwise  both
    operands shall be converted to unsigned long int.

  --Otherwise,  if  either operand is long, the other shall be converted
    to long.

  _________________________
  1) As a consequence, operands of type bool, wchar_t, or an  enumerated
  type are converted to some integral type.

  --Otherwise, if either operand is unsigned, the other  shall  be  con-
    verted to unsigned.

  [Note:  otherwise,  the  only remaining case is that both operands are
  int ]

10The values of the  floating  operands  and  the  results  of  floating
  expressions  may  be  represented  in greater precision and range than
  that required by the type; the types are not changed thereby.2)

  5.1  Primary expressions                                   [expr.prim]

1 Primary expressions are literals, names, and names  qualified  by  the
  scope resolution operator ::.
          primary-expression:
                  literal
                  this
                  :: identifier
                  :: operator-function-id
                  :: qualified-id
                  ( expression )
                  id-expression

          id-expression:
                  unqualified-id
                  qualified-id

2 A  literal  is  a  primary  expression.   Its type depends on its form
  (_lex.literal_).  A string literal is an lvalue;  all  other  literals
  are rvalues.

3 The  keyword  this names a pointer to the object for which a nonstatic
  member function (_class.this_) is invoked.  The keyword this shall  be
  used only inside a nonstatic class member function body (_class.mfct_)
  or in a constructor mem-initializer (_class.base.init_).  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 oper-
  ator-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-func-
  tion-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 names-
  pace declared in the global namespace to be referred to  even  if  its
  _________________________
  2) The cast and assignment operators must still perform their specific
  conversions  as  described in _expr.cast_, _expr.static.cast_ and _ex-
  pr.ass_.

  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_).  ]
          id-expression:
                  unqualified-id
                  qualified-id

          unqualified-id:
                  identifier
                  operator-function-id
                  conversion-function-id
                  ~ class-name
                  template-id

7 An  identifier  is  an  id-expression  provided  it  has been suitably
  declared   (_dcl.dcl_).    [Note:   for   operator-function-ids,   see
  _over.oper_;  for  conversion-function-ids,  see _class.conv.fct_; 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 trans-
  formed  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.

8         qualified-id:
                  nested-name-specifier templateopt unqualified-id
          nested-name-specifier:
                  class-or-namespace-name :: nested-name-specifieropt

          class-or-namespace-name:
                  class-name
                  namespace-name
  A nested-name-specifier that names a class, optionally followed by the
  keyword  template (_temp.arg.explicit_), and then followed by the name
  of a member of either that class (_class.mem_)  or  one  of  its  base
  classes  (_class.derived_),  is a qualified-id; _class.qual_ describes
  name look up for class members  that  appear  in  qualified-ids.   The
  result  is the member.  The type of the result is the type of the mem-
  ber.  The result is an lvalue if the member is a static  member  func-
  tion 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.  ]

9 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  quali-
  fied-id; _namespace.qual_ describes name look up 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.

10In a qualified-id, if the id-expression is  a  conversion-function-id,
  its  conversion-type-id shall denote the same type in both the context
  in which the entire qualified-id occurs and  in  the  context  of  the
  class denoted by the nested-name-specifier.

11An  id-expression  that  denotes  a nonstatic data member or nonstatic
  member function of a class can only be used:

  --as part of a class member access (_expr.ref_) in which  the  object-
    expression refers to the member's class or a class derived from that
    class, or

  --to form a pointer to member (_expr.unary.op_), or

  --in the body of a nonstatic member function of that  class  or  of  a
    class derived from that class (_class.mfct.nonstatic_), or

  --in a mem-initializer for a constructor for that class or for a class
    derived from that class (_class.base.init_).

12A template-id shall be used as an unqualified-id only as specified  in
  clauses _temp.explicit_, _temp.spec_, and _temp.class.spec_.

  5.2  Postfix expressions                                   [expr.post]

1 Postfix expressions group left-to-right.

          postfix-expression:
                  primary-expression
                  postfix-expression [ expression ]
                  postfix-expression ( expression-listopt )
                  simple-type-specifier ( expression-listopt )
                  postfix-expression . templateopt ::opt id-expression
                  postfix-expression -> templateopt ::opt id-expression
                  postfix-expression . pseudo-destructor-name
                  postfix-expression -> pseudo-destructor-name
                  postfix-expression ++
                  postfix-expression --
                  dynamic_cast < type-id > ( expression )
                  static_cast < type-id > ( expression )
                  reinterpret_cast < type-id > ( expression )
                  const_cast < type-id > ( expression )
                  typeid ( expression )
                  typeid ( type-id )
          expression-list:
                  assignment-expression
                  expression-list , assignment-expression
          pseudo-destructor-name:
                  ::opt nested-name-specifieropt type-name :: ~ type-name
                  ::opt nested-name-specifieropt ~ type-name

  5.2.1  Subscripting                                         [expr.sub]

1 A postfix expression followed by an expression in square brackets is a
  postfix expression.  One  of  the  expressions  shall  have  the  type
  "pointer  to T" and the other shall have enumeration or integral type.
  The result is an lvalue of type "T."  The type "T"  shall  be  a  com-
  pletely-defined object type.3) The expression E1[E2] is identical  (by
  definition)  to  *((E1)+(E2)).  [Note: see _expr.unary_ and _expr.add_
  for details of * and + and _dcl.array_ for details of arrays.  ]

  5.2.2  Function call                                       [expr.call]

1 There are two kinds of function call: ordinary function call and  mem-
  ber function4) (_class.mfct_) call.  A  function  call  is  a  postfix
  expression followed by parentheses containing a possibly empty, comma-
  separated list of expressions which constitute the  arguments  to  the
  function.  For an ordinary function call, the postfix expression shall
  be either an lvalue that refers to a function (in which case the func-
  tion-to-pointer standard conversion (_conv.func_) is suppressed on the
  postfix expression), or it shall have pointer to function type.  Call-
  ing  a  function  through an expression whose function type has a lan-
  guage linkage that is different from the language linkage of the func-
  tion   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
  _________________________
  3)  This is true even if the subscript operator is used in the follow-
  ing common idiom: &x[0].
  4)  A static member function (_class.static_) is an ordinary function.

  explicit class member access (_expr.ref_)  whose  id-expression  is  a
  function    member    name,    or   a   pointer-to-member   expression
  (_expr.mptr.oper_) selecting a function member.  The first  expression
  in  the  postfix  expression is then called the object expression, and
  the call is as a member of the object pointed to or referred  to.   In
  the case of an implicit class member access, the implied object is the
  one pointed to by this.  [Note: a member function call of the form f()
  is  interpreted  as  (*this).f() (see _class.mfct.nonstatic_).  ] If a
  function or member function name is used, the name can  be  overloaded
  (_over_),  in  which  case  the appropriate function shall be selected
  according to the rules in _over.match_.  The function called in a mem-
  ber function call is normally selected according to the static type of
  the object expression (see _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.  Clause _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 ini-
  tialized (_dcl.init_, _class.copy_, _class.ctor_) with its correspond-
  ing  argument.   When  a  function is called, the parameters that have
  object type shall have completely-defined object  type.   [Note:  this
  still allows a parameter to be a pointer or reference to an incomplete
  class type.  However, it prevents a passed-by-value parameter to  have
  an incomplete class type.  ] During the initialization of a parameter,
  an implementation may avoid the construction of extra  temporaries  by
  combining  the  conversions on the associated argument and/or the con-
  struction of temporaries with the initialization of the parameter (see
  _class.temporary_).   The  lifetime of a parameter ends when the func-
  tion in which it is defined returns.  The initialization and  destruc-
  tion  of each parameter occurs within the context of the calling func-
  tion.  [Example: the access of the constructor,  conversion  functions
  or destructor is checked at the point of call in the calling function.
  If a constructor or destructor for  a  function  parameter  throws  an
  exception, the search for a handler starts in the scope of the calling
  function; in particular, if the function called  has  a  function-try-
  block  (_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  mod-
  ify 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 func-
  tion 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 (_class_), the behavior is undefined.  If the argument  has
  integral  or  enumeration  type that is subject to the integral promo-
  tions (_conv.prom_), or a floating point type that is subject  to  the
  floating point promotion (_conv.fpprom_), the value of the argument is
  converted to the promoted type before the call.  These promotions  are
  referred to as the default argument promotions.

8 The order of evaluation of arguments is unspecified.  All side effects
  of argument expression evaluations take effect before the function  is
  entered.   The  order  of evaluation of the postfix expression and the
  argument expression list is unspecified.

9 Recursive calls are permitted.

10A function call is an lvalue if and only if the result type is a  ref-
  erence.

  5.2.3  Explicit type conversion (functional           [expr.type.conv]
       notation)

1 A  simple-type-specifier  (_dcl.type_)  followed  by  a  parenthesized
  expression-list  constructs  a  value  of the specified type given the
  expression list.  If the expression list 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.sim-
  ple_) for a non-array complete object type or the (possibly  cv-quali-
  fied)  void type, creates an rvalue of the specified type, whose value
  is determined by default-initialization (_dcl.init_).  [Note: if T  is
  a  non-class  type that is cv-qualified, the cv-qualifiers are ignored
  when determining the type of the resulting rvalue (_basic.lval_).  ]

  5.2.4  Pseudo destructor call                            [expr.pseudo]

1 The use of a pseudo-destructor-name after a dot .  or arrow ->  opera-
  tor  represents  the  destructor for the non-class type named by type-
  name.  The result shall only be used as the operand for  the  function
  call  operator  (),  and the result of such a call has type void.  The
  only effect is the evaluation of the postfix-expression before the dot
  or arrow.

2 The  left  hand side of the dot operator shall be of scalar type.  The
  left hand side of the arrow operator shall be  of  pointer  to  scalar
  type.   This  scalar  type is the object type.  The type designated by
  the pseudo-destructor-name shall be the same as the object type.  Fur-
  thermore, the two type-names in a pseudo-destructor-name of the form
          ::opt nested-name-specifieropt type-name :: ~ type-name
  shall designate the same scalar type.

  5.2.5  Class member access                                  [expr.ref]

1 A  postfix  expression followed by a dot .  or an arrow ->, optionally
  followed by the keyword template (_temp.arg.explicit_), and then  fol-
  lowed  by  an  id-expression,  is  a  postfix expression.  The postfix
  expression before the dot or arrow is evaluated;5) the result of  that
  evaluation,  together  with the id-expression, determine the result of
  the entire postfix expression.

2 For the first option (dot) the  type  of  the  first  expression  (the
  object  expression) shall be "class object" (of a complete type).  For
  the second option (arrow)  the  type  of  the  first  expression  (the
  pointer  expression) shall be "pointer to class object" (of a complete
  type).  In these cases, the id-expression shall name a member  of  the
  class  or  of  one  of its base classes.  [Note: because the name of a
  class is inserted in its class scope (_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.  ]

  _________________________
  5) This evaluation happens even if the result is unnecessary to deter-
  mine  the  value  of the entire postfix expression, for example if the
  id-expression denotes a static member.

3 If E1 has the type "pointer to class X," then the expression E1->E2 is
  converted to the equivalent form (*(E1)).E2;  the  remainder  of  this
  subclause will address only the first  option  (dot)6).   Abbreviating
  object-expression.id-expression  as  E1.E2,  then  the type and lvalue
  properties of this expression  are  determined  as  follows.   In  the
  remainder of this subclause, cq represents either const or the absence
  of const; vq represents either volatile or the  absence  of  volatile.
  cv  represents  an  arbitrary  set  of  cv-qualifiers,  as  defined in
  _basic.type.qualifier_.

4 If E2 is declared to have type "reference to  T",  then  E1.E2  is  an
  lvalue; the type of E1.E2 is T.  Otherwise, one of the following rules
  applies.

  --If E2 is a static data member, and the type of E2 is T,  then  E1.E2
    is  an  lvalue;  the  expression  designates the named member of the
    class.  The type of E1.E2 is T.

  --If E2 is a non-static data member, and the type of E1  is  "cq1  vq1
    X", and the type of E2 is "cq2 vq2 T", the expression designates the
    named member of the object designated by the first  expression.   If
    E1  is  an  lvalue,  then E1.E2 is an lvalue.  Let the notation vq12
    stand for the "union" of vq1 and vq2 ; that is, if  vq1  or  vq2  is
    volatile,  then  vq12 is volatile.  Similarly, let the notation cq12
    stand for the "union" of cq1 and cq2; that is,  if  cq1  or  cq2  is
    const,  then  cq12 is const.  If E2 is declared to be a mutable mem-
    ber, then the type of E1.E2 is "vq12 T".  If E2 is not  declared  to
    be a mutable member, then the type of E1.E2 is "cq12 vq12 T".

  --If  E2 is a (possibly overloaded) member function, function overload
    resolution (_over.match_) is used to determine whether E1.E2  refers
    to a static or a non-static member function.

    --If  it  refers  to a static member function, and the type of E2 is
      "function of (parameter type list) returning T", then E1.E2 is  an
      lvalue; the expression designates the static member function.  The
      type of E1.E2 is the same type as that of E2, namely "function  of
      (parameter type list) returning T".

    --Otherwise,  if  E1.E2  refers to a non-static member function, and
      the type of E2 is "function of (parameter type list) cv  returning
      T", then E1.E2 is not an lvalue.  The expression designates a non-
      static member function.  The expression can be used  only  as  the
      left-hand  operand  of  a  member  function  call  (_class.mfct_).
      [Note: any redundant set of parentheses surrounding the expression
      is  ignored  (_expr.prim_).   ]  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.

  _________________________
  6)  Note that if E1 has the type "pointer to class X", then (*(E1)) is
  an lvalue.

  --If E2 is a member enumerator, and the type of E2 is T,  the  expres-
    sion E1.E2 is not an lvalue.  The type of E1.E2 is T.

5 [Note:  "class  objects"  can  be  structures (_class.mem_) and unions
  (_class.union_).  Classes are discussed in clause _class_.  ]

  5.2.6  Increment and decrement                        [expr.post.incr]

1 The value obtained by applying a postfix ++  is  the  value  that  the
  operand  had  before applying the operator.  [Note: the value obtained
  is a copy of the original value ] The operand shall  be  a  modifiable
  lvalue.   The  type  of  the  operand shall be an arithmetic type or a
  pointer to 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 con-
  verting the expression v to type T.  T shall be a pointer or reference
  to a complete class type, or "pointer to cv void".  Types shall not be
  defined in a dynamic_cast.  The dynamic_cast operator shall  not  cast
  away constness (_expr.const.cast_).

2 If  T is a pointer type, v shall be an rvalue of a pointer to complete
  class type, and the result is an rvalue of type T.  If T is  a  refer-
  ence  type,  v  shall  be  an lvalue of a complete class type, and the
  result is an lvalue of the type referred to by T.

3 If the type of v is the same as the required result type  (which,  for
  convenience,  will be called R in this description), or it 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 unique7) B sub-object of the D object
  referred to by v.  In both the pointer and reference cases, cv1  shall
  _________________________
  7) The most derived object (_intro.object_) pointed or referred to  by
  v  can contain other B objects as base classes, but these are ignored.

  be  the  same  cv-qualification  as, or greater cv-qualification than,
  cv2, and B shall be an accessible unambiguous base class of D.  [Exam-
  ple:
          struct B {};
          struct D : B {};
          void foo(D* dp)
          {
              B*  bp = dynamic_cast<B*>(dp);  // equivalent to B* bp = dp;
          }
   --end example]

6 Otherwise,  v shall be a pointer to or an lvalue of a polymorphic type
  (_class.virtual_).

7 If T is "pointer to cv void," then the result is a pointer to the most
  derived  object  pointed  to  by  v.   Otherwise,  a run-time check is
  applied to see if the object pointed or referred to by v can  be  con-
  verted to the type pointed or referred to by T.

8 The run-time check logically executes as follows:

  --If,  in the most derived object pointed (referred) to by v, v points
    (refers) to a public base class sub-object of a  T  object,  and  if
    only  one  object  of  type T is derived from the sub-object pointed
    (referred) to by v, the result is a pointer (an lvalue referring) to
    that T object.

  --Otherwise, if v points (refers) to a public base class sub-object of
    the most derived object, and the type of the most derived object has
    an  unambiguous public base class of type T, the result is a pointer
    (an lvalue referring) to  the  T  sub-object  of  the  most  derived
    object.

  --Otherwise, the run-time check fails.

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*>(&dr);      // succeeds
              bp = dynamic_cast<B*>(&dr);      // fails
          }

          class E : public D, public B {};
          class F : public E, public D {};
          void h()
          {
              F   f;
              A*  ap  = &f;                    // succeeds: finds unique A
              D*  dp  = dynamic_cast<D*>(ap);  // fails: yields 0
                                               // f has two D sub-objects
              E*  ep  = (E*)ap;                // ill-formed:
                                               // cast from virtual base
              E*  ep1 = dynamic_cast<E*>(ap);  // succeeds
          }
    --end example] [Note: Clause _class.cdtor_ describes the behavior of
  a dynamic_cast applied to an object under construction or destruction.
  ]

  5.2.8  Type identification                               [expr.typeid]

1 The  result  of  a  typeid  expression  is  an  lvalue  of  type const
  std::type_info (_lib.type.info_).  The lifetime of the object referred
  to  by  the  lvalue extends to the end of the program.  Whether or not
  the destructor is called for the type_info object at the  end  of  the
  program is unspecified.

2 When  typeid  is applied to an lvalue expression whose type is a poly-
  morphic class type (_class.virtual_), the result refers to a type_info
  object   representing   the   type   of   the   most   derived  object
  (_intro.object_) (that is, the  dynamic  type)  to  which  the  lvalue
  refers.   If the lvalue expression is obtained by applying the unary *
  operator  to  a  pointer8)  and  the  pointer  is a null pointer value
  (_conv.ptr_), the typeid expression throws  the  bad_typeid  exception
  (_lib.bad.typeid_).

3 When  typeid  is  applied  to  an expression other than an lvalue of a
  polymorphic class type, the result refers to a type_info object repre-
  senting   the   static   type  of  the  expression.   Lvalue-to-rvalue
  (_conv.lval_),  array-to-pointer  (_conv.array_),   and   function-to-
  pointer  (_conv.func_)  conversions are not applied to the expression.
  If the type of the expression is a class type, the class shall be com-
  pletely-defined.  The expression is not evaluated.

4 When  typeid is applied to a type-id, the result refers to a type_info
  object representing the type of the type-id.  If the type of the type-
  id  is a reference type, the result of the typeid expression refers to
  a type_info object representing the referenced type.  If the  type  of
  the  type-id is a class type or a reference to a class type, the class
  shall be completely-defined.  Types shall not be defined in the  type-
  id.

  _________________________
  8) If p is an expression of pointer type, then *p, (*p), *(p), ((*p)),
  *((p)), and so on all meet this requirement.

5 The  top-level  cv-qualifiers  of the lvalue expression or the type-id
  that is the operand of typeid are always ignored.  [Example:
          class D { ... };
          D d1;
          const D d2;
          typeid(d1) == typeid(d2);      // yields true
          typeid(D)  == typeid(const D); // yields true
          typeid(D)  == typeid(d2);      // yields true
          typeid(D)  == typeid(const D&);// yields true
   --end example]

6 If the header <typeinfo> (_lib.type.info_) is not included prior to  a
  use of typeid, the program is ill-formed.

7 [Note:  clause  _class.cdtor_ describes the behavior of typeid applied
  to an object under construction or destruction.  ]

  5.2.9  Static cast                                  [expr.static.cast]

1 The result of the expression static_cast<T>(v) is the result  of  con-
  verting  the  expression  v  to type T.  If T is a reference type, the
  result is an lvalue; otherwise, the result is an rvalue.  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  vari-
  able as the result of the conversion.  The result is an lvalue if T is
  a reference type (_dcl.ref_), and an rvalue otherwise.  The expression
  e is used as an lvalue if and only if the 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  vari-
  able  is not executed until the usual time, and the value of the vari-
  able 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  (_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
   --end example]

6 The  inverse  of any standard conversion sequence (_conv_), other than
  the lvalue-to-rvalue (_conv.lval_),  array-to-pointer  (_conv.array_),
  function-to-pointer  (_conv.func_),  and boolean (_conv.bool_) conver-
  sions, can be performed explicitly using static_cast  subject  to  the
  restriction  that the explicit conversion does not cast away constness
  (_expr.const.cast_), and the following additional rules  for  specific
  cases:

7 A value of integral type can be explicitly converted to an enumeration
  type.  The value is unchanged if the  integral  value  is  within  the
  range of the enumeration values (_dcl.enum_). Otherwise, the resulting
  enumeration value is unspecified.

8 An rvalue of type "pointer to cv1 B", where B is a class type, can  be
  converted  to an rvalue of type "pointer to cv2 D", where D is a class
  derived (_class.derived_) from B, if a valid standard conversion  from
  "pointer  to 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  con-
  verted  to  an  rvalue of type "pointer to member of B of type cv2 T",
  where B is a base class (_class.derived_) of D, if  a  valid  standard
  conversion from "pointer to member of B of type T" to "pointer to mem-
  ber of D of type T" exists (_conv.mem_), and cv2 is the same cv-quali-
  fication as, or greater cv-qualification than, cv1.9) 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  mem-
  ber,  or is a base or derived class of the class containing the origi-
  nal 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_.  ]
  _________________________
  9)  Function types (including those used in pointer to member function
  types) are never cv-qualified; see _dcl.fct_ .

  5.2.10  Reinterpret cast                       [expr.reinterpret.cast]

1 The result of the expression reinterpret_cast<T>(v) is the  result  of
  converting  the expression v to type T.  If T is a reference type, the
  result is an lvalue; otherwise,  the  result  is  an  rvalue  and  the
  lvalue-to-rvalue  (_conv.lval_),  array-to-pointer (_conv.array_), and
  function-to-pointer (_conv.func_) standard conversions  are  performed
  on  the  the  expression  v.  Types shall not be defined in a reinter-
  pret_cast.  Conversions that can be performed explicitly  using  rein-
  terpret_cast  are  listed below.  No other conversion can be performed
  explicitly using reinterpret_cast.

2 The reinterpret_cast operator shall not cast away  constness.   [Note:
  see  _expr.const.cast_  for  the  definition  of ``casting away const-
  ness''.  ] Any expression may be cast to its own type using a reinter-
  pret_cast operator.

3 The  mapping  performed by reinterpret_cast is implementation-defined.
  [Note: it might, or might not, produce a representation different from
  the original value.  ]

4 A  pointer  can  be  explicitly  converted  to any integral type large
  enough to hold it.  The  mapping  function  is  implementation-defined
  [Note:  it  is  intended  to  be  unsurprising  to  those who know the
  addressing structure of the underlying machine.  ]

5 A value of integral type or enumeration type can  be  explicitly  con-
  verted to a pointer.10) A pointer converted to an  integer  of  suffi-
  cient  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.11) 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
  _________________________
  10)  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.
  11) The types may have different cv-qualifiers, subject to the overall
  restriction that a reinterpret_cast cannot cast away constness.

  stricter than those of T1) and back to its original  type  yields  the
  original  pointer  value,  the  result of such a pointer conversion is
  unspecified.

8 The null pointer value (_conv.ptr_) is converted to the  null  pointer
  value of the destination type.

9 An  rvalue  of type "pointer to member of X of type T1" can be explic-
  itly converted to an rvalue of type "pointer to member of  Y  of  type
  T2" if T1 and T2 are both function types or both object types.12)  The
  null member pointer value (_conv.mem_) is converted to the null member
  pointer value of the destination type.  The result of this  conversion
  is unspecified, except in the following cases:

  --converting  an rvalue of type "pointer to member function" to a dif-
    ferent pointer to member function type and back to its original type
    yields the original pointer to member value.

  --converting  an  rvalue  of type "pointer to data member of X of type
    T1" to the type "pointer to data member of Y of type T2" (where  the
    alignment  requirements  of T2 are no stricter than those of T1) and
    back to its original type yields  the  original  pointer  to  member
    value.

10Calling  a member function through a pointer to member that represents
  a function type (_dcl.fct_) that differs from the function type speci-
  fied  on the member function definition results in undefined behavior,
  except when calling a virtual function  whose  function  type  differs
  from  the  function type of the pointer to member only as permitted by
  the rules for overriding virtual functions (_class.virtual_).

11An lvalue expression of type T1 can be cast to the type "reference  to
  T2"  if  an  expression of type "pointer to T1" can be explicitly con-
  verted 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 *  opera-
  tors.   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.13)

  5.2.11  Const cast                                   [expr.const.cast]

1 The result of the expression const_cast<T>(v) is of type T.  If T is a
  reference  type,  the result is an lvalue; otherwise, the result is an
  rvalue  and,  the  lvalue-to-rvalue  (_conv.lval_),   array-to-pointer
  (_conv.array_), and function-to-pointer (_conv.func_) standard conver-
  sions are performed on the expression v.  Types shall not  be  defined
  in  a  const_cast.  Conversions that can be performed explicitly using
  _________________________
  12) T1 and T2 may have different cv-qualifiers, subject to the overall
  restriction that a reinterpret_cast cannot cast away constness.
  13) This is sometimes referred to as a type pun.

  const_cast are listed below.  No other conversion shall  be  performed
  explicitly using const_cast.

2 Any  expression  may be cast to its own type using a const_cast opera-
  tor.

3 For two pointer types T1 and T2 where

            T1 is cv1,0 pointer to cv1,1 pointer to ... cv1,n-1 pointer to cv1,n T
  and

            T2 is cv2,0 pointer to cv2,1 pointer to ... cv2,n-1 pointer to cv2,n T
  where 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 des-
  tination 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-qualifier14) may produce undefined
  behavior (_dcl.type.cv_).  ]

8 The  following  rules  define the process known as casting away const-
  ness.  In these rules Tn and Xn  represent  types.   For  two  pointer
  types:

            X1 is T1cv1,1 * ... cv1,N *   where T1 is not a pointer type
            X2 is T2cv2,1 * ... cv2,M *   where T2 is not a pointer type
            K is min(N,M)
  casting  from X1 to X2 casts away constness if, for a non-pointer type
  _________________________
  14) const_cast is not limited to conversions that cast away  a  const-
  qualifier.

  T there does not exist an implicit conversion (_conv_) from:

            Tcv1,(N-K+1) * cv1,(N-K+2) * ... cv1,N *
  to

            Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *

9 Casting from an lvalue of type T1 to an lvalue of type T2 using a ref-
  erence  cast  casts  away  constness  if a cast from an rvalue of type
  "pointer to T1" to the type "pointer to T2" casts away constness.

10Casting 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.

11For  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
                  *  &  +  -  !  ~

  5.3.1  Unary operators                                 [expr.unary.op]

1 The unary * operator performs indirection: the expression to which  it
  is  applied  shall  be  a pointer to an object type, or a pointer to a
  function type and the result is an lvalue referring to the  object  or
  function  to  which the expression points.  If the type of the expres-
  sion is "pointer to T," the type of  the  result  is  "T."   [Note:  a
  pointer  to  an  incomplete type (other than cv void ) can be derefer-
  enced.  The lvalue thus obtained can be used in limited ways (to  ini-
  tialize  a  reference, for example); this lvalue must not be converted

  to an rvalue, see _conv.lval_.  ]

2 The result of the unary & operator is a pointer to its  operand.   The
  operand  shall  be an lvalue or a qualified-id.  In the first case, if
  the type of the expression is "T," the type of the result is  "pointer
  to  T."   In  particular,  the  address of an object of type "cv T" is
  "pointer to cv T," with the same cv-qualifiers.  For  a  qualified-id,
  if  the  member is a static member of type "T", the type of the result
  is plain "pointer to T."  If the member is a nonstatic member of class
  C  of  type T, the type of the result is "pointer to member of class C
  of type T."  [Example:
          struct A { int i; };
          struct B : A { };
          ... &B::i ... // has type "int A::*"
   --end example] [Note: a pointer to member formed from a mutable  non-
  static  data member (_dcl.stc_) does not reflect the mutable specifier
  associated with the nonstatic data member.  ]

3 A pointer to member is only formed when an explicit & is used and  its
  operand  is  a  qualified-id not enclosed in parentheses.  [Note: that
  is, the expression &(qualified-id), where the qualified-id is enclosed
  in  parentheses,  does not form an expression of type "pointer to mem-
  ber."  Neither does qualified-id, because there is no implicit conver-
  sion  from  a qualified-id for a nonstatic member function to the type
  "pointer to member function" as there is from an  lvalue  of  function
  type to the type "pointer to function" (_conv.func_).  Nor is &unqual-
  ified-id a pointer to member, even within the scope  of  the  unquali-
  fied-id's class.  ]

4 The  address  of an object of incomplete type can be taken, but if the
  complete type of that object is a class type that declares operator&()
  as  a member function, then the behavior is undefined (and no diagnos-
  tic is required).  The operand of & shall not be a bit-field.

5 The address of an overloaded function (_over_) can be taken only in  a
  context that uniquely determines which version of the overloaded func-
  tion is referred to (see _over.over_).  [Note: since the context might
  determine  whether  the  operand is a static or nonstatic member func-
  tion, the context can also affect  whether  the  expression  has  type
  "pointer to function" or "pointer to member function."  ]

6 The  operand  of  the unary + operator shall have arithmetic, enumera-
  tion, or pointer type and the result is the  value  of  the  argument.
  Integral  promotion  is performed on integral or enumeration operands.
  The type of the result is the type of the promoted operand.

7 The operand of the unary - operator shall have arithmetic or  enumera-
  tion  type  and  the  result is the negation of its operand.  Integral
  promotion is performed on integral or enumeration operands.  The nega-
  tive of an unsigned quantity is computed by subtracting its value from
  2n, where n is the number of bits in the promoted operand.   The  type
  of the result is the type of the promoted operand.

8 The  operand  of  the  logical negation operator !  is implicitly con-
  verted to bool (_conv_); its value is true if the converted operand is
  false and false otherwise.  The type of the result is bool.

9 The  operand  of ~ shall have integral or enumeration type; the result
  is the one's complement of its operand.  Integral promotions are  per-
  formed.   The  type of the result is the type of the promoted operand.
  There is an ambiguity in the  unary-expression  ~X(),  where  X  is  a
  class-name.   The  ambiguity  is  resolved in favor of treating ~ as a
  unary complement rather than treating ~T as referring to a destructor.

  5.3.2  Increment and decrement                         [expr.pre.incr]

1 The operand of prefix ++ is modified by adding 1, or set to true if it
  is bool (this use is deprecated).  The operand shall be  a  modifiable
  lvalue.   The  type  of  the  operand shall be an arithmetic type or a
  pointer to a completely-defined object type.  The  value  is  the  new
  value  of the operand; it is an lvalue.  If x is not of type bool, the
  expression ++x is equivalent to x+=1.  [Note: see the  discussions  of
  addition (_expr.add_) and assignment operators (_expr.ass_) for infor-
  mation on conversions.  ]

2 The operand of prefix -- is modified by substracting 1.   The  operand
  shall  not be of type bool.  The requirements on the operand of prefix
  -- and the properties of its result are otherwise the same as those of
  prefix   ++.    [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 represen-
  tation  of its operand.  The operand is either an expression, which is
  not evaluated, or a parenthesized type-id.  The sizeof operator  shall
  not  be applied to an expression that has function or incomplete type,
  or to an  enumeration  type  before  all  its  enumerators  have  been
  declared,  or to the parenthesized name of such types, or to an lvalue
  that designates a bit-field.  sizeof(char),  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.15) ] [Note: See _intro.memory_ for the defini-
  tion  of byte and _basic.types_ for the definition of object represen-
  tation.  ]

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.16) When applied to an array, the result is the  total
  _________________________
  15) sizeof(bool) is not required to be 1.
  16) The actual size of a base class subobject may be less than the re-

  number  of bytes in the array.  This implies that the size of an array
  of n elements is n times the size of an element.

3 The sizeof operator can be applied to a pointer  to  a  function,  but
  shall not be applied directly to a function.

4 The  lvalue-to-rvalue  (_conv.lval_), array-to-pointer (_conv.array_),
  and function-to-pointer (_conv.func_)  standard  conversions  are  not
  applied to the operand of sizeof.

5 Types shall not be defined in a sizeof expression.

6 The  result  is  a constant of an implementation-defined type which is
  the same type as that which is named size_t  in  the  standard  header
  <cstddef>(_lib.support.types_).

  5.3.4  New                                                  [expr.new]

1 The  new-expression  attempts  to  create  an  object  of  the type-id
  (_dcl.name_) to which it is applied.  This type shall  be  a  complete
  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 ]
          new-initializer:
                  ( expression-listopt )
  Entities created by a new-expression  have  dynamic  storage  duration
  (_basic.stc.dynamic_).   [Note:  the lifetime of such an entity is not
  necessarily restricted to the scope in which it is created.  ] If  the
  entity  is 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.

2 The  new-type-id  in a new-expression is the longest possible sequence
  of  new-declarators.   [Note:  this   prevents   ambiguities   between
  _________________________
  sult  of applying sizeof to the subobject, due to virtual base classes
  and less strict padding requirements on base class subobjects.

  declarator  operators  &, *, [], and their expression counterparts.  ]
  [Example:
          new int*i;     // syntax error: parsed as `(new int*) i'
                         //               not as `(new int)*i'
  The * is the pointer declarator and not the  multiplication  operator.
  ]

3 Parentheses shall not appear in the new-type-id of a new-expression.

4 [Example:
          new int(*[10])();       // error
  is ill-formed because the binding is
          (new int) (*[10])();    // error
  Instead,  the explicitly parenthesized version of the new operator can
  be used to create objects of compound types (_basic.compound_):
          new (int (*[10])());
  allocates an array of 10 pointers to functions (taking no argument and
  returning int).  ]

5 The  type-specifier-seq  shall not contain class declarations, or enu-
  meration declarations.

6 When the allocated object  is  an  array  (that  is,  the  direct-new-
  declarator  syntax  is  used  or the new-type-id or type-id denotes an
  array type), the new-expression yields a pointer to the  initial  ele-
  ment  (if any) of the array.  [Note: both new int and new int[10] have
  type int* and the type of new int[i][10] is int (*)[10].  ]

7 Every constant-expression in a direct-new-declarator shall be an inte-
  gral  constant  expression  (_expr.const_)  and evaluate to a strictly
  positive value.  The expression in a direct-new-declarator shall  have
  integral type (_basic.fundamental_) with a non-negative value.  [Exam-
  ple: if n is a variable of type int,  then  new float[n][5]  is  well-
  formed  (because  n is the expression of a direct-new-declarator), but
  new float[5][n] is ill-formed (because n  is  not  a  constant-expres-
  sion).   If n is negative, the effect of new float[n][5] is undefined.
  ]

8 When the value of the expression in a direct-new-declarator  is  zero,
  the  allocation  function  is called to allocate an array with no ele-
  ments.  The pointer returned by the  new-expression  is  non-null  and
  distinct from the pointer to any other object.

9 Storage  for  the  object created by a new-expression is obtained from
  the appropriate allocation function  (_basic.stc.dynamic.allocation_).
  When  the  allocation  function is called, the first argument shall be
  the amount of space requested (which shall be no less than the size of
  the object being created and which may be greater than the size of the
  object being created only if the object is an array).

10An implementation shall provide default  definitions  for  the  global
  allocation    functions    operator new()    for    non-array    types
  (_basic.stc.dynamic_,  _lib.new.delete.single_)  and  operator new[]()
  for  array  types  (_lib.new.delete.array_).  [Note: A C++ program can

  provide alternative  definitions  of  these  functions  (_lib.replace-
  ment.functions_),  and/or  class-specific  versions (_class.free_).  ]
  When the keyword new in a new-expression is preceded by the  unary  ::
  operator, the global allocation function is used to allocate the stor-
  age.

11The new-placement syntax is used to supply additional arguments to  an
  allocation  function.   If used, overload resolution is performed on a
  function call created by assembling an argument list consisting of the
  amount  of space requested (the first argument) and the expressions in
  the new-placement part of the new-expression (the second and  succeed-
  ing  arguments).  The first of these arguments has type size_t and the
  remaining arguments have the corresponding types of the expressions in
  the new-placement.

12[Example:

  --new T results in a call of operator new(sizeof(T)),

  --new(2,f) T results in a call of operator new(sizeof(T),2,f),

  --new T[5] results in a call of operator new[](sizeof(T)*5+x), and

  --new(2,f) T[5]        results        in        a        call       of
    operator new[](sizeof(T)*5+y,2,f).

  Here, x and y are non-negative, implementation-defined  values  repre-
  senting  array  allocation  overhead.  Their value might vary from one
  invocation of new to another.  ]

13The allocation function shall either return null or  a  pointer  to  a
  block  of  storage  in  which  space  for  the  object shall have been
  reserved.  [Note: the block of storage is assumed to be  appropriately
  aligned  and  of the requested size. The address of the created object
  will not necessarily be the same as that of the block if the object is
  an array.  ]

14A  new-expression  that  creates  an object of type T initializes that
  object as follows:

  --If the new-initializer is omitted:

    --If T is a (possibly cv-qualified) non-POD  class  type  (or  array
      thereof), the object is default-initialized (_dcl.init_).  If T is
      a const-qualified type, the underlying class  type  shall  have  a
      user-declared default constructor.

    --Otherwise,  the object created has indeterminate value.  If T is a
      const-qualified type, or a (possibly cv-qualified) POD class  type
      (or array thereof) containing (directly or indirectly) a member of
      const-qualified type, the program is ill-formed;

  --If the new-initializer is of  the  form  (),  default-initialization

    shall be performed (_dcl.init_);

  --If  the  new-initializer  is of the form expression-list) and T is a
    class type, the appropriate constructor is called, using expression-
    list as the arguments (_dcl.init_);

  --If  the  new-initializer is of the form expression-list) and T is an
    arithmetic, enumeration,  pointer,  or  pointer-to-member  type  and
    expression-list comprises exactly one expression, then the object is
    initialized to the (possibly  converted)  value  of  the  expression
    (_dcl.init_);

  --Otherwise the new-expression is ill-formed.

15If  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 construc-
  tor (_class.ctor_).  If the new expression creates an array of objects
  of  class type, access and ambiguity control are done for the destruc-
  tor (_class.dtor_).

16The allocation function can indicate failure by throwing  a  bad_alloc
  exception (_except_, _lib.bad.alloc_).  In this case no initialization
  is done.

17If any part of the object initialization described above17) terminates
  by throwing an exception and the new-expression  does  not  contain  a
  new-placement,        then       the       deallocation       function
  (_basic.stc.dynamic.deallocation_, _class.free_) is called to free the
  memory  in  which  the  object  was being constructed, after which the
  exception continues to propagate in the context of the new-expression.

18If any part of the object initialization described above terminates by
  throwing an exception and the new-expression contains a new-placement,
  if the type of the object being created is a class type, a name lookup
  is performed on the name of operator  delete  using  the  same  lookup
  rules as those used to find operator new (_class.free_).  Otherwise, a
  name lookup is performed on the name of operator delete in  the  scope
  of  the new-expression (or in global scope for ::new ).  If the lookup
  succeeds and exactly one of the declarations found matches the  decla-
  ration  of  that  placement  operator new, then the matching placement
  operator delete shall  be  called  (_basic.stc.dynamic.deallocation_).
  If  no  matching  placement delete is found, propagating the exception
  does not cause the object to be deleted.  [Note: this  is  appropriate
  when  the  called operator new does not allocate memory; otherwise, it
  is likely to result in a memory leak.  ]

19A declaration of placement operator delete matches the declaration  of
  a  placement  operator  new  when it has the same number of parameters
  and, after parameter transformations (_dcl.fct_), all parameter  types
  _________________________
  17) This may include evaluating a  new-initializer  and/or  calling  a
  constructor.

  except the first are identical.

20If  placement  operator  delete is called, it is passed the same argu-
  ments as were passed to placement operator new.  If the implementation
  is  allowed to make a copy of an argument as part of the placement new
  call, it is allowed to make a copy (of the  same  original  value)  as
  part  of  the placement delete call, or to reuse the copy made as part
  of the placement new call.  If the copy is elided  in  one  place,  it
  need not be elided in the other.

21The  way the object was allocated determines how it is freed: if it is
  allocated by ::new, then it is freed by ::delete,  and  if  it  is  an
  array, it is freed by delete[] or ::delete[] as appropriate.

22Whether  the  allocation function is called before evaluating the con-
  structor arguments or after evaluating the constructor  arguments  but
  before  entering  the constructor is unspecified.  It is also unspeci-
  fied whether the arguments to a constructor are evaluated if the allo-
  cation  function returns the null pointer or exits using an exception.

  5.3.5  Delete                                            [expr.delete]

1 The  delete-expression  operator  destroys  a  most   derived   object
  (_intro.object_) or array created by a new-expression.
          delete-expression:
                  ::opt delete cast-expression
                  ::opt delete [ ] cast-expression
  The  first alternative is for non-array objects, and the second is for
  arrays.  The operand shall have a pointer type, or a class type having
  a  single  conversion  function  (_class.conv.fct_) to a pointer type.
  The result has type void.

2 If the operand has a class type, the operand is converted to a pointer
  type  by calling the above-mentioned conversion function, and the con-
  verted 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  created  by  a  new-
  expression, or a pointer to a sub-object (_intro.object_) representing
  a base class of such an object (_class.derived_).  If not, the  behav-
  ior 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.18) If not, the behavior is unde-
  fined.  [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
  _________________________
  18)  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.

  used as the operand of the delete-expression.  ]

3 In  the  first  alternative (delete object), if the static type of the
  operand is different from its dynamic type, the static type shall be a
  base  class  of  the  operand's dynamic type and the static type shall
  have a virtual destructor or the behavior is undefined.  In the second
  alternative  (delete  array)  if  the dynamic type of the object to be
  deleted differs from its static type, the behavior is undefined.19)

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 To  free  the  storage  pointed  to, the delete-expression will call a
  deallocation function (_basic.stc.dynamic.deallocation_).

8 An implementation provides default definitions of the global dealloca-
  tion  functions operator delete() for non-arrays (_lib.new.delete.sin-
  gle_) 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 func-
  tion and the destructor (_class.dtor_, _class.free_).

  5.4  Explicit type conversion (cast notation)              [expr.cast]

1 The result of the expression (T) cast-expression is of  type  T.   The
  result  is an lvalue if T is a reference type, otherwise the result is
  an rvalue.  [Note: if T is a non-class type that is cv-qualified,  the
  cv-qualifiers  are  ignored when determining the type of the resulting
  rvalue; see _basic.lval_.  ]

  _________________________
  19) This implies that an object cannot be deleted using a  pointer  of
  type void* because there are no objects of type void.

2 An explicit type conversion can be expressed using functional notation
  (_expr.type.conv_),  a   type   conversion   operator   (dynamic_cast,
  static_cast, reinterpret_cast, const_cast), or the cast notation.
          cast-expression:
                  unary-expression
                  ( type-id ) cast-expression

3 Types shall not be defined in casts.

4 Any  type conversion not mentioned below and not explicitly defined by
  the user (_class.conv_) is ill-formed.

5 The conversions performed by

  --a const_cast (_expr.const.cast_),

  --a static_cast (_expr.static.cast_),

  --a static_cast followed by a const_cast,

  --a reinterpret_cast (_expr.reinterpret.cast_), or

  --a reinterpret_cast followed by a const_cast,

  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]

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  reinter-
  pret_cast interpretation is used is unspecified.

7 In  addition to those conversions, the following static_cast and rein-
  terpret_cast operations (optionally followed by  a  const_cast  opera-
  tion)  may  be performed using the cast notation of explicit type con-
  version, even if the base class type is not accessible:

  --a pointer to an object of derived class type or an lvalue of derived
    class  type may be explicitly converted to a pointer or reference to

    an unambiguous base class type, respectively;

  --a pointer to member of derived class type  may  be  explicitly  con-
    verted  to  a  pointer  to member of an unambiguous non-virtual base
    class type;

  --a pointer to an object of non-virtual base class type, an lvalue  of
    non-virtual  base  class type, or a pointer to member of non-virtual
    base class type may be explicitly converted to a pointer,  a  refer-
    ence,  or a pointer to member of a derived class type, respectively.

  5.5  Pointer-to-member operators                      [expr.mptr.oper]

1 The pointer-to-member operators ->* and .*  group left-to-right.
          pm-expression:
                  cast-expression
                  pm-expression .* cast-expression
                  pm-expression ->* cast-expression

2 The binary operator .*  binds its second operand, which  shall  be  of
  type  "pointer  to member of T" (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  exam-
  ple,
          struct S {
                  mutable int i;
          };
          const S cs;
          int S::* pm = &S::i; // pm refers to mutable member S::i
          cs.*pm = 88;         // ill-formed: cs is a const class
  ]

6 If  the  result  of  .*  or ->* is a function, then that result can be
  used only as the operand for the function call operator ().  [Example:
          (ptr_to_obj->*ptr_to_mfct)(10);
  calls  the  member  function  denoted  by  ptr_to_mfct  for the object
  pointed to by ptr_to_obj.  ] The result of  a  .*   expression  is  an

  lvalue  only  if its first operand is an lvalue and its second operand
  is a pointer to data member.  The result of an ->*  expression  is  an
  lvalue only if its second operand is a pointer to data member.  If the
  second operand is the null pointer to member value  (_conv.mem_),  the
  behavior is undefined.

  5.6  Multiplicative operators                               [expr.mul]

1 The multiplicative operators *, /, and % group left-to-right.
          multiplicative-expression:
                  pm-expression
                  multiplicative-expression * pm-expression
                  multiplicative-expression / pm-expression
                  multiplicative-expression % pm-expression

2 The operands of * and / shall have arithmetic or enumeration type; the
  operands of % shall have integral  or  enumeration  type.   The  usual
  arithmetic conversions are performed on the operands and determine the
  type of the result.

3 The binary * operator indicates multiplication.

4 The binary / operator yields the quotient, and the binary  %  operator
  yields  the remainder from the division of the first expression by the
  second.  If the second operand of / or % is zero the behavior is unde-
  fined;  otherwise  (a/b)*b  + a%b is equal to a.  If both operands are
  nonnegative then the remainder is nonnegative; if not, the sign of the
  remainder is implementation-defined20).

  5.7  Additive operators                                     [expr.add]

1 The additive operators + and - group left-to-right.  The usual  arith-
  metic conversions are performed for operands of arithmetic or enumera-
  tion type.
          additive-expression:
                  multiplicative-expression
                  additive-expression + multiplicative-expression
                  additive-expression - multiplicative-expression
  For addition, either both operands shall have arithmetic  or  enumera-
  tion  type,  or one operand shall be a pointer to a completely defined
  object type and the other shall have integral or enumeration type.

2 For subtraction, one of the following shall hold:

  --both operands have arithmetic or enumeration type; or

  --both operands are pointers to cv-qualified  or  cv-unqualified  ver-
    sions of the same completely defined object type; or
  _________________________
  20)  According to work underway toward the revision of ISO C, the pre-
  ferred algorithm for integer division follows the rules defined in the
  ISO  Fortran standard, ISO/IEC 1539:1991, in which the quotient is al-
  ways rounded toward zero.

  --the  left  operand  is a pointer to a completely defined object type
    and the right operand has integral or enumeration type.

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  ele-
  ments.   The  type  of  the result is an implementation-defined signed
  integral type; this type shall be the same type  that  is  defined  as
  ptrdiff_t  in the <cstddef> header (_lib.support.types_).  As with any
  other arithmetic overflow, if the result does not  fit  in  the  space
  provided,  the  behavior is undefined.  In other words, if the expres-
  sions P and Q point to, respectively, the i-th and j-th elements of an
  array  object,  the  expression (P)-(Q) has the value i-j provided the
  value fits in an object of type ptrdiff_t.  Moreover, if  the  expres-
  sion  P points either to an element of an array object or one past the
  last element of an array object, and the expression Q  points  to  the
  last  element of the same array object, the expression ((Q)+1)-(P) has
  the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value
  zero if the expression P points one past the last element of the array
  object, even though the expression (Q)+1 does not point to an  element
  of  the  array  object.  Unless both pointers point to elements of the
  same array object, or one past the last element of the  array  object,
  the behavior is undefined.21)
  _________________________
  21) 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

8 If  the  value  0  is added to or subtracted from a pointer value, the
  result compares equal to the original pointer value.  If two  pointers
  point to the same object or function or both point one past the end of
  the same array or both are null, and the two pointers are  subtracted,
  the  result  compares  equal  to  the  value  0  converted to the type
  ptrdiff_t.

  5.8  Shift operators                                      [expr.shift]

1 The shift operators << and >> group left-to-right.
          shift-expression:
                  additive-expression
                  shift-expression << additive-expression
                  shift-expression >> additive-expression
  The operands shall be of integral or  enumeration  type  and  integral
  promotions  are performed.  The type of the result is that of the pro-
  moted left operand.  The behavior is undefined if the right operand is
  negative,  or  greater than or equal to the length in bits of the pro-
  moted left operand.

2 The value of E1 << E2 is E1  (interpreted  as  a  bit  pattern)  left-
  shifted  E2 bit positions; vacated bits are zero-filled.  If E1 has an
  unsigned type, the value of the result is E1 multiplied by  the  quan-
  tity  2  raised  to the power E2, reduced modulo ULONG_MAX+1 if E1 has
  type  unsigned  long,  UINT_MAX+1  otherwise.   [Note:  the  constants
  ULONG_MAX and UINT_MAX are defined in the header <climits>).  ]

3 The value of E1 >> E2 is E1 right-shifted E2 bit positions.  If E1 has
  an unsigned type or if E1 has a signed type and a  nonnegative  value,
  the  value  of  the  result is the integral part of the quotient of E1
  divided by the quantity 2 raised to the power E2.  If E1 has a  signed
  type  and  a  negative  value,  the resulting value is implementation-
  defined.

  5.9  Relational operators                                   [expr.rel]

1 The relational operators group left-to-right.  [Example:  a<b<c  means
  (a<b)<c and not (a<b)&&(b<c).  ]

  _________________________
  the  resulting  pointer  is  converted back to the original type.  For
  pointer subtraction, the result of the difference between the  charac-
  ter pointers is similarly divided by the size of the object originally
  pointed to.

7 When viewed in this way, an implementation need only provide one extra
  byte  (which  might  overlap another object in the program) just after
  the end of the object in order to satisfy the "one past the last  ele-
  ment" requirements.

          relational-expression:
                  shift-expression
                  relational-expression < shift-expression
                  relational-expression > shift-expression
                  relational-expression <= shift-expression
                  relational-expression >= shift-expression
  The  operands shall have arithmetic, enumeration or pointer type.  The
  operators < (less than), > (greater than), <= (less than or equal to),
  and  >=  (greater than or equal to) all yield false or true.  The type
  of the result is bool.

2 The usual arithmetic conversions are performed on operands  of  arith-
  metic or enumeration type.  Pointer conversions (_conv.ptr_) and qual-
  ification 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  con-
  stant,  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-qualifica-
  tion 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.   ]
  Pointers  to objects or functions of the same type (after pointer con-
  versions) can be compared, with a result defined as follows:

  --If two pointers p and q of the same type point to the same object or
    function,  or  both point one past the end of the same array, or are
    both null, then p<=q and p>=q both yield true and p<q and  p>q  both
    yield false.

  --If  two pointers p and q of the same type point to different objects
    that are not members of the same object  or  elements  of  the  same
    array or to different functions, or if only one of them is null, the
    results of p<q, p>q, p<=q, and p>=q are unspecified.

  --If two pointers point to nonstatic data members of the same  object,
    the  pointer  to the later declared member compares greater provided
    the two members are  not  separated  by  an  access-specifier  label
    (_class.access.spec_) and provided their class is not a union.

  --If  two  pointers point to nonstatic data members of the same object
    separated by an  access-specifier  label  (_class.access.spec_)  the
    result is unspecified.

  --If two pointers point to data members of the same union object, they
    compare equal (after conversion to void*,  if  necessary).   If  two
    pointers  point  to elements of the same array or one beyond the end
    of the array, the pointer to the object with  the  higher  subscript
    compares higher.

  --Other pointer comparisons are unspecified.

  5.10  Equality operators                                     [expr.eq]

1         equality-expression:
                  relational-expression
                  equality-expression == relational-expression
                  equality-expression != relational-expression
  The  ==  (equal  to) and the != (not equal to) operators have the same
  semantic restrictions, conversions, and result type as the  relational
  operators  except  for  their lower precedence and truth-value result.
  [Note: a<b == c<d is true whenever a<b and c<d have  the  same  truth-
  value.  ]

2 In addition, pointers to members can be compared, or a pointer to mem-
  ber 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  con-
  stant,  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  func-
  tion,  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 derefer-
  enced with a hypothetical object of the associated class type.  [Exam-
  ple:
          struct B {
                  int f();
          };
          struct L : B { };
          struct R : B { };
          struct D : L, R { };
          int (B::*pb)() = &B::f;
          int (L::*pl)() = pb;
          int (R::*pr)() = pb;
          int (D::*pdl)() = pl;
          int (D::*pdr)() = pr;
          bool x = (pdl == pdr);    // false
   --end example]

  5.11  Bitwise AND operator                              [expr.bit.and]

1         and-expression:
                  equality-expression
                  and-expression & equality-expression
  The usual arithmetic conversions are performed; the result is the bit-
  wise function of the operands.  The operator applies only to  integral
  or enumeration operands.

  5.12  Bitwise exclusive OR operator                         [expr.xor]

1         exclusive-or-expression:
                  and-expression
                  exclusive-or-expression ^ and-expression
  The usual arithmetic conversions are performed; the result is the bit-
  wise exclusive function of the operands.  The operator applies only to
  integral or enumeration operands.

  5.13  Bitwise inclusive OR operator                          [expr.or]

1         inclusive-or-expression:
                  exclusive-or-expression
                  inclusive-or-expression | exclusive-or-expression
  The usual arithmetic conversions are performed; the result is the bit-
  wise inclusive function of its operands.  The operator applies only to
  integral or enumeration operands.

  5.14  Logical AND operator                              [expr.log.and]

1         logical-and-expression:
                  inclusive-or-expression
                  logical-and-expression && inclusive-or-expression
  The  &&  operator groups left-to-right.  The operands are both implic-
  itly converted to type bool (_conv_).  The  result  is  true  if  both
  operands  are true and false otherwise.  Unlike &, && guarantees left-
  to-right evaluation: the second operand is not evaluated if the  first
  operand is false.

2 The result is a bool.  All side effects of the first expression except
  for destruction of temporaries (_class.temporary_) happen  before  the
  second expression is evaluated.

  5.15  Logical OR operator                                [expr.log.or]

1         logical-or-expression:
                  logical-and-expression
                  logical-or-expression || logical-and-expression
  The  ||  operator groups left-to-right.  The operands are both implic-
  itly converted to bool (_conv_).  It returns true  if  either  of  its
  operands  is true, and false otherwise.  Unlike |, || guarantees left-
  to-right evaluation; moreover, the second operand is not evaluated  if
  the first operand evaluates to true.

2 The result is a bool.  All side effects of the first expression except
  for destruction of temporaries (_class.temporary_) happen  before  the
  second expression is evaluated.

  5.16  Conditional operator                                 [expr.cond]

1         conditional-expression:
                  logical-or-expression
                  logical-or-expression ? expression : assignment-expression
  Conditional  expressions group right-to-left.  The first expression is

  implicitly converted to bool (_conv_).  It is evaluated and if  it  is
  true,  the  result  of  the conditional expression is the value of the
  second expression, otherwise that of the third expression.   All  side
  effects  of the first expression except for destruction of temporaries
  (_class.temporary_) happen before the second or  third  expression  is
  evaluated.  Only one of the second and third expressions is evaluated.

2 If either the second or the third operand has type (possibly cv-quali-
  fied)  void, then the lvalue-to-rvalue (_conv.lval_), array-to-pointer
  (_conv.array_), and function-to-pointer (_conv.func_) standard conver-
  sions  are  performed on the second and third operands, and one of the
  following shall hold:

  --The second or the third operand (but not both) is a throw-expression
    (_except.throw_);  the  result is of the type of the other and is an
    rvalue.

  --Both the second and the third operands have type void; the result is
    of  type void and is an rvalue.  [Note: this includes the case where
    both operands are throw-expressions.  ]

3 Otherwise, if either the second or the third operand has (possibly cv-
  qualified)  class  or enumeration type, overload resolution is used to
  determine the conversions (if any)  to  be  applied  to  the  operands
  (_over.match.oper_,  _over.built_).   The  conversions thus determined
  are applied, and the converted operands are used in place of the orig-
  inal operands for the remainder of this section.

4 If  the  second and third operands are lvalues and have the same type,
  the result is of that type and is an lvalue.

5 Otherwise, the result is an rvalue.   Lvalue-to-rvalue  (_conv.lval_),
  array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_)
  standard conversions are performed on the second and  third  operands.
  After those conversions, one of the following shall hold:

  --The  second  and third operands have the same type; the result is of
    that type.

  --The second and third operands have arithmetic or  enumeration  type;
    the  usual  arithmetic  conversions are performed to bring them to a
    common type, and the result is of that type.

  --The second and third operands have pointer type, or one has  pointer
    type  and  the other is a null pointer constant; pointer conversions
    (_conv.ptr_) and qualification conversions  (_conv.qual_)  are  per-
    formed  to  bring them to their composite pointer type (_expr.rel_).
    The result is of the composite pointer type.

  --The second and third operands have pointer to member  type,  or  one
    has pointer to member type and the other is a null pointer constant;
    pointer to member conversions (_conv.mem_) and qualification conver-
    sions  (_conv.qual_)  are  performed to bring them to a common type,
    whose cv-qualification shall match the  cv-qualification  of  either

    the  second or the third operand.  The result is of the common type.

  5.17  Assignment operators                                  [expr.ass]

1 There are several assignment operators, all of which  group  right-to-
  left.   All require a modifiable lvalue as their left operand, and the
  type of an assignment expression is that of  its  left  operand.   The
  result  of  the  assignment  operation is the value stored in the left
  operand after the assignment has taken place; the result is an lvalue.
          assignment-expression:
                  conditional-expression
                  logical-or-expression assignment-operator assignment-expression
                  throw-expression
          assignment-operator: one of
                  =  *=  /=  %=   +=  -=  >>=  <<=  &=  ^=  |=

2 In simple assignment (=), the value of the expression replaces that of
  the object referred to by the left operand.

3 If the left operand is not of class type, the expression is implicitly
  converted (_conv_) to the cv-unqualified type of the left operand.

4 If  the  left  operand  is of class type, the class shall be complete.
  Assignment to objects of a class 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 refer-
  ence.

7 The  behavior  of an expression of the form E1 op= E2 is equivalent to
  E1=E1 op E2 except that E1 is evaluated only once.  In += and  -=,  E1
  shall  either  have  arithmetic 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.

  5.18  Comma operator                                      [expr.comma]

1 The comma operator groups left-to-right.
          expression:
                  assignment-expression
                  expression , assignment-expression
  A pair of expressions separated by a comma is evaluated  left-to-right
  and  the  value  of  the left expression is discarded.  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.tempo-
  rary_), are performed before the evaluation of the  right  expression.
  The  type  and value of the result are the type and value of the right
  operand; the result is an lvalue if its right operand is.

2 In contexts where comma is given a special meaning, [Example: in lists
  of  arguments  to  functions  (_expr.call_)  and lists of initializers
  (_dcl.init_) ] the comma operator as  described  in  this  clause  can
  appear only in parentheses.  [Example:
          f(a, (t=3, t+2), c);
  has three arguments, the second of which has the value 5.  ]

  5.19  Constant expressions                                [expr.const]

1 In  several places, C++ requires expressions that evaluate to an inte-
  gral  or  enumeration  constant:   as   array   bounds   (_dcl.array_,
  _expr.new_), as case expressions (_stmt.switch_), as bit-field lengths
  (_class.bit_), as enumerator initializers (_dcl.enum_), as static mem-
  ber initializers (_class.static.data_), and as integral or enumeration
  non-type template arguments (_temp.arg_).
          constant-expression:
                  conditional-expression
  An integral constant-expression can involve only  literals  (_lex.lit-
  eral_),  enumerators,  const variables or static data members of inte-
  gral  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.

2 Other  expressions  are  considered  constant-expressions only for the
  purpose     of     non-local     static     object      initialization
  (_basic.start.init_).  Such constant expressions shall evaluate to one
  of the following:

  --a null pointer value (_conv.ptr_),

  --a null member pointer value (_conv.mem_),

  --an arithmetic constant expression,

  --an address constant expression,

  --a reference constant expression,

  --an address constant expression for a complete object type,  plus  or
    minus an integral constant expression, or

  --a pointer to member constant expression.

3 An arithmetic constant expression shall have arithmetic or enumeration
  type  and  shall  only  have  operands  that  are   integer   literals
  (_lex.icon_),  floating  literals (_lex.fcon_), enumerators, character
  literals (_lex.ccon_) and sizeof  expressions  (_expr.sizeof_).   Cast
  operators  in  an  arithmetic  constant  expression shall only convert
  arithmetic or enumeration types to arithmetic  or  enumeration  types,
  except as part of an operand to the sizeof operator.

4 An  address  constant expression is a pointer to an lvalue designating
  an object of static storage duration, a string literal (_lex.string_),
  or  a  function.   The  pointer shall be created explicitly, using the
  unary & operator, or implicitly using a non-type template parameter of
  pointer  type, or using an expression of array (_conv.array_) or func-
  tion (_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.   An
  expression  that designates the address of a member or base class of a
  non-POD class object (_class_) is not an address  constant  expression
  (_class.cdtor_).   Function calls shall not be used in an address con-
  stant 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
  An  lvalue expression that designates a member or base class of a non-
  POD class object (_class_) is  not  a  reference  constant  expression
  (_class.cdtor_).  Function calls shall not be used in a reference con-
  stant 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_).