2010-11-17 18 views
10

ich auf diese verzichten ...dynamic_cast Verwirrung

$ 5.2.7/2- „Wenn T ein Zeigertyp ist, v wird ein R-Wert eines Zeigers auf komplette Klassentyp sein, und die Ergebnis ist ein R-Wert des Typs T. Wenn T ein Referenztyp ist, sollte v ein L-Wert eines vollständigen Klassentyps sein, und das Ergebnis ist ein L-Wert des Typs , auf den sich T bezieht. "

In Übereinstimmung mit dem oben genannten sollte der folgende Code wohlgeformt sein.

struct A{}; 
struct B : A{}; 

int main(){ 
    B b; 
    A a, &ar1 = b; 

    B& rb1 = dynamic_cast<B&>(ar1); // Does not $5.2.7/2 apply here? 
    B& rb2 = dynamic_cast<B&>(a); // and also here? 
} 

Aber es ist nicht. Alle Compiler über die Operanden nicht beschweren dynamic_cast mit

$ 5.2.7/6- Ansonsten gemäß polymorphen ist, v wird ein Zeiger auf oder ein L-Wert eines polymorphen Typ (10.3) liegen.

Also meine Frage ist, was bedeutet $ 5.2.7/2? Warum tritt $ 5.2.7/6 hier ein?

Antwort

3

"Sonst" bedeutet in diesem Fall, "es sei denn, die Bedingungen in 5.2.7/5 gelten".

Sie können dies sagen, weil/2 Plätze eine Anforderung an das Programm über den Operanden des der dynamic_cast (man beachte das „soll“ Sprache „v wird ein L-Wert sein“ gegen die Sprache des „Ergebnis„ist“ ist ein Wert "). Wie bei anderen Stellen im Standard bedeutet auch das Ausdrücken einer Anforderung nicht unbedingt, dass es sich um die Anforderung nur handelt. Andere Klauseln können zusätzliche Anforderungen enthalten. In diesem Fall gibt/6 eine zusätzliche Anforderung an, die nur in bestimmten Fällen in Abhängigkeit von T und dem statischen Typ von v

/3,/4,/5 über den Wert des Ergebnisses gilt und sie stimmen vollständig mit der Anforderung in/2 überein. Keiner von ihnen beginnt mit "Sonst". Für mich ist es ziemlich offensichtlich, dass sie ab/2 keine "else if" -Kette bilden.

Einige Klammern oder etwas könnte dies deutlicher machen (dh dass das "sonst" in/6 für das "if" in/5 gilt und nicht für das "if" in/2,/3 oder/4) . Aber das ist einfach nicht der Hausstil.

Abgesehen von allem anderen kann das "sonst" in/5 logisch nicht sinnvoll auf die Bedingungen in/2 angewendet werden./1 besagt, dass T "Zeiger oder Verweis auf den vollständigen Klassentyp oder cvvoid*" sein muss./2 behandelt zwei Fälle - Zeigertypen und Referenztypen. Das ist alles. Es gibt kein "sonst" zu/2 (es sei denn, es würde heißen "sonst muss ein kompilierender Compiler eine Diagnose ausgeben", aber das ist implizit)

+0

gibt es einen anderen Fall, wo "sonst" im Standard in einer * potenziell * unklaren Weise verwendet wird – Chubsdad

+0

@Chubsdad: Ich erwarte so. –

+0

Was ist der Unterschied s/w 'soll' und 'wird' wie im Standard verwendet? – Chubsdad

9

Nun, alle Anforderungen in 5.2.7 sind zu beachten zusammen. Du kannst nicht einfach nach 5.2.7/2 aufhören und Code schreiben, der angeblich alles "bis 5.2.7/2" erfüllt. Das gesamte 5.2.7 definiert die Spezifikation dynamic_cast.

Die polymorphe Anforderung wird herausgegriffen, weil sie bedingt ist. Wenn Sie dynamic_cast für Upcasts verwenden, gilt die polymorphe Anforderung nicht (tatsächlich entspricht dynamic_cast in Upcasts static_cast). Die polymorphe Anforderung gilt nur, wenn Sie dynamic_cast für Downcasts oder Crosscasts verwenden.

Die Spezifikation von dynamic_cast ist sequenziell organisiert, was bedeutet, dass es zuerst einfachere Fälle behandelt und dann zu komplizierteren Anwendungen übergeht. Sie sollten es Schritt für Schritt lesen, bis es Ihre spezifische Situation abdeckt. Alles, was Sie entlang dieses Pfades lesen, gilt kumulativ. Und "sonst" bedeutet: "Wenn wir Ihren Fall noch nicht behandelt haben, lesen Sie weiter".

+2

Mmmm. Okay. Aber was bedeutet "sonst"? – sharptooth

+0

genau meine Frage. Der Benutzer von "sonst" in vielen anderen Teilen des Standards gibt eine Art "schrittweises" algorithmisches Vorgehen. – Chubsdad

+0

Danke AndreyT. Ich denke, Steve hat es in einer Weise ausgedrückt, die überzeugend war. Das "andere" gilt für 5.2.7/5 statt für alle vorherigen Klauseln. Ich hoffe, dass solche Verwirrungen einen Weg haben, den Standardausschuss für potenzielle Adressaten zu erreichen. – Chubsdad

4

Um ein downcast wie in Ihrem Beispiel zu machen, muss Struct A polymorph sein und RTTI haben. Hier ist eine angepasste Version, die bis zu einem Punkt funktioniert:

struct A{virtual void f(){}}; 
struct B : A{}; 

int main(){ 
    B b; 
    A a, &ar1 = b; 

    B& rb1 = dynamic_cast<B&>(ar1); // Does not $5.2.7/2 apply here? 
    //B& rb2 = dynamic_cast<B&>(a); // and also here? 
} 

durch eine virtuelle Hinzufügen es polymorphe machen, wird RTTI für die Klasse freigegeben, so dass downcasts.

Beachten Sie, dass Ihr zweites Beispiel nicht funktionieren kann - da Sie einen Pod (a) auf einen Verweis auf einen Pod werfen - was nicht erlaubt ist.


Update:

Ihr Code wird nicht unter 5.2.7.5 erlaubt und ist weder unter 5.2.7.6 erlaubt. Meine Einstellung funktioniert unter 5.2.7.6

+0

Danke Alex. Aber das ist nicht meine Frage. – Chubsdad