static_cast ambiguity: conversion versus cast to derived
Section [expr.static.cast]
Mark Mitchell

Created on 2003-07-05.00:00:00 last changed 162 months ago


Date: 2004-10-15.00:00:00

[Voted into WP at October 2004 meeting.]

Date: 2003-10-15.00:00:00

Proposed Resolution (October 2003):

Move paragraph 5.2.9/5:

An lvalue of type ``cv1 B'', where B is a class type, can be cast to type ``reference to cv2 D'', where D is a class derived (clause 11.7 [class.derived]) from B, if a valid standard conversion from ``pointer to D'' to ``pointer to B'' exists (7.3.12 [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]

before paragraph [expr.static.cast]/2.

Insert Otherwise, before the text of paragraph [expr.static.cast]/2 (which will become [expr.static.cast]/3 after the above insertion), so that it reads:

Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration "T t(e);" is well-formed, for some invented temporary variable t (9.4 [dcl.init]). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The result is an lvalue if T is a reference type ( [dcl.ref]), and an rvalue otherwise. The expression e is used as an lvalue if and only if the initialization uses it as an lvalue.

Date: 2003-07-05.00:00:00

Consider this code:

  struct B {};

  struct D : public B { 
    D(const B&);

  extern B& b;

  void f() {
    static_cast<const D&>(b);

The rules for static_cast permit the conversion to "const D&" in two ways:

  1. D is derived from B, and b is an lvalue, so a cast to D& is OK.
  2. const D& t = b is valid, using the constructor for D. [Ed. note: actually, this should be parenthesized initialization.]

The first alternative is [expr.static.cast]/5; the second is [expr.static.cast]/2.

Presumably the first alternative is better -- it's the "simpler" conversion. The standard does not seem to make that clear.

Steve Adamczyk: I take the "Otherwise" at the beginning of [expr.static.cast]/3 as meaning that the paragraph 2 interpretation is used if available, which means in your example above interpretation 2 would be used. However, that's not what EDG's compiler does, and I agree that it's not the "simpler" conversion.

Date User Action Args
2008-10-05 00:00:00adminsetstatus: wp -> cd1
2005-05-01 00:00:00adminsetstatus: dr -> wp
2004-11-07 00:00:00adminsetmessages: + msg1094
2004-11-07 00:00:00adminsetstatus: ready -> dr
2004-04-09 00:00:00adminsetstatus: review -> ready
2003-11-15 00:00:00adminsetmessages: + msg921
2003-11-15 00:00:00adminsetstatus: open -> review
2003-07-05 00:00:00admincreate