3

I've come across with the follwing code (sec. 5.4/4 N3797):

struct A { };
struct I1 : A { };
struct I2 : A { };
struct D : I1, I2 { };
A* foo( D* p ) {
    return (A*)( p ); // ill-formed static_cast interpretation
}

I have been trying to understand the example, but I can't. I haven't used static_cast in the example at all. How does it relate to static_cast. In general, would you explain the point of the error.

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • 6
    `A` isn't a virtual base. I.e. there is no diamond pattern here. Thus there are *two* `A`'s laid out in a `D`. So which `A` do you expect the result of `foo()` to be addressing, the one `I1` derives from, or the one `I2` derives from? The ambiguity is the reason for the error. – WhozCraig Aug 02 '14 at 14:59
  • Check out Virtual Inheritance: http://en.wikipedia.org/wiki/Virtual_inheritance – dari Aug 02 '14 at 15:03
  • @WhozCraig What's the diamond pattern? – St.Antario Aug 02 '14 at 15:04
  • 1
    @St.Antario there *isn't one*. That's the point. If there were *one* "instance" of `A` "shared" as the base of *both* `I1` and `I2` you would have one. [See this answer](http://stackoverflow.com/questions/21558/in-c-what-is-a-virtual-base-class/112474#112474). (and looking back at your comment, I see you asked "What", not "Where". Sorry for the confusion. Hope that linked answer helps (it should). – WhozCraig Aug 02 '14 at 15:04
  • @WhozCraig At what is the static_cast? – St.Antario Aug 02 '14 at 15:05
  • "I haven't used static_cast in the example at all". Too bad, because you should, in preference of the old C-style casts. – n. m. could be an AI Aug 02 '14 at 15:14
  • @St.Antario jxh just saved me the time of pasting the standard citation. See that answer. its an order-of-application thing. – WhozCraig Aug 02 '14 at 15:15
  • @n.m. Why? What's bad in C-style casts? – St.Antario Aug 02 '14 at 15:15
  • [This is too broad for a comment](https://www.google.com/search?q=C-style+casts+are+bad). – n. m. could be an AI Aug 02 '14 at 17:15

1 Answers1

3

The "C style cast" is called "explicit type conversion", and is discussed in §5.4 if the C.11 standard. In ¶4:

The conversions performed by
— a const_cast (5.2.11),
— a static_cast (5.2.9),
— a static_cast followed by a const_cast,
— a reinterpret_cast (5.2.10), or
— a reinterpret_cast followed by a const_cast,
can be performed using the cast notation of explicit type conversion.

Which is basically saying a static_cast may be the result of a cast expression. It then lists some conditions under which it is a valid static_cast, and the example you cite was an example when it was invalid. Just before that example was the following text (the very end of ¶4):

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.

The reason the example listed is ill-formed is because both I1 and I2 do non-virtual inheritance from A. Thus, D, which uses multiple inheritance on I1 and I2 will have two A instances within it, and so trying to cast a D * to an A * has more than one interpretation. The programmer needs to specify which A * instance should result to avoid an ill-formed conversion.

ASCII art alert:

+---+          +---+
| A |          | A |
+---+          +---+
  |              |
 /_\            /_\
  |              |
+----+         +----+
| I1 |         | I2 |
+----+         +----+
  |              |
  +------.-------+
         |
        /_\
         |
       +---+
       | D |
       +---+
jxh
  • 69,070
  • 8
  • 110
  • 193
  • +1 for the citation. The OP should note the term *"explicit type conversion"*, which denotes the application of `(T)`; in this case `T` is `A*`. – WhozCraig Aug 02 '14 at 15:19
  • How to determine how many ways to interpret an appropriate cast-expression? – St.Antario Aug 03 '14 at 07:48
  • The conversions are applied in the order above, and the first one that can be used is the one used, even if it is ill-formed. The reason for ill-formed is not that more than one applies, but that the choice for `A *` is ambiguous. – jxh Aug 03 '14 at 14:47
  • "*The programmer needs to specify which `A *` instance should result to avoid an ill-formed conversion.*" Do you mean something like this `return (D::I1::A*)(p)` ? If so, the cast is still ill-formed! –  Mar 10 '22 at 12:43
  • @cpper I didn't specify how to do that. You should be able to cast to `I1 *` or `I2 *` first, and then convert that pointer to `A *`. – jxh Mar 10 '22 at 18:05