2010-11-17 4 views
10

mi arrendo su questo ...dynamic_cast confusione

$ 5.2.7/2- "Se T è un tipo di puntatore, v sarà un rvalue di un puntatore a tipo di classe completa, e il risultato è un rvalue di tipo T. Se T è un tipo riferimento, v è un Ivalue di un tipo di classe completo, e il risultato è un Ivalue del tipo cui da T."

In conformità a quanto sopra, il seguente codice deve essere ben formato.

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? 
} 

Ma non lo è. Tutti i compilatori lamentano l'operando per dynamic_cast non essere polimorfica secondo

$ 5.2.7/6- In caso contrario, V è un puntatore o un lvalue di tipo polimorfico (10.3).

Quindi la mia domanda è cosa significa $ 5.2.7/2? Perché kick $ 5.2.7/6 entra qui?

risposta

3

"Altrimenti" significa in questo caso ", a meno che non si applichino le condizioni in 5.2.7/5".

Si può dire questo perché/2 pone un requisito sul programma per quanto riguarda l'operando del dynamic_cast (si noti la lingua "deve" di "v deve essere un lvalue" rispetto alla "è" lingua di "il risultato è un lvalue "). In comune con altri punti dello standard, l'espressione di un requisito non significa necessariamente che sia il requisito solo. Altre clausole possono indicare requisiti aggiuntivi. In questo caso,/6 indica un requisito aggiuntivo che si applica solo in alcuni casi, a seconda di T e il tipo statico di v.

/3,/4,/5 ti dice del valore del risultato e sono del tutto coerenti con il requisito in/2. Nessuno di loro inizia con "Altrimenti". Quindi per me è abbastanza ovvio che non formano una catena "else if" a partire da/2.

Alcune parentesi o qualcosa potrebbe rendere questo più chiaro (cioè che "altrimenti" in/6 si applica a "se" in/5, e non a "if" in/2,/3 o/4) . Ma questo non è solo lo stile della casa.

Oltre a qualsiasi altra cosa, il "altrimenti" in/5 logicamente non può applicarsi significativamente alle condizioni in/2./1 dice che T deve essere "puntatore o riferimento per completare il tipo di classe, oppure cvvoid*"./2 riguarda due casi: tipi di puntatore e tipi di riferimento. Questo è tutto. Non c'è "altrimenti" a/2 (a meno che non si dica "altrimenti, un compilatore conforme deve emettere una diagnostica", ma è implicito)

+0

c'è qualche altro caso in cui 'altrimenti' nello Standard viene utilizzato in un * potenzialmente * non chiaro modo – Chubsdad

+0

@Chubsdad: mi aspetto così. –

+0

qual è la differenza b/n "deve" e "sarà" come utilizzato nello standard? – Chubsdad

9

Bene, tutti i requisiti in 5.2.7 devono essere rispettati insieme. Non puoi fermarti dopo il 5.2.7/2 e iniziare a scrivere il codice che suppone soddisfi tutto "fino a 5.2.7/2". L'intero 5.2.7 definisce le specifiche di dynamic_cast.

Il requisito polimorfico è individuato perché è condizionale. Quando si utilizza dynamic_cast per gli aggiornamenti, il requisito polimorfico non si applica (infatti,è equivalente a static_cast in upcast). Il requisito polimorfico si applica solo quando si utilizza dynamic_cast per i downcast o i crosscast.

La specifica di dynamic_cast è organizzata in sequenza, il che significa che si prende cura dei casi più semplici, e poi procede ad applicazioni più complesse. Dovresti leggerlo passo dopo passo, finché non copre la tua situazione specifica. Tutto ciò che leggi lungo quel percorso si applica cumulativamente, e "altrimenti" significa: "se non abbiamo ancora coperto il tuo caso, allora continua a leggere".

+2

Mmmm. Va bene. Ma cosa significa "altrimenti"? – sharptooth

+0

esattamente la mia domanda. L'utente di "altrimenti" in molte altre parti dello Standard dà il tipo di procedere algoritmico "graduale". – Chubsdad

+0

Grazie AndreyT. Penso che Steve l'abbia messo in un modo che è stato convincente. Il 'altrimenti' si applica a 5.2.7/5 invece di tutte le clausole precedenti. Spero che tali confusioni abbiano un modo per raggiungere il comitato standard per potenziali indirizzi. – Chubsdad

4

Per eseguire un downcast come nell'esempio, Struct A deve essere polimorfico e avere RTTI. Ecco una versione rivista che funziona, a un certo punto:

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? 
} 

Con l'aggiunta di un virtuale rendendolo polimorfa, RTTI è abilitata per la classe, permettendo downcasts.

Si noti che il secondo esempio non può funzionare, dal momento che si sta trasmettendo un pod (a) a un riferimento a un pod, che non è consentito.


Aggiornamento:

Il codice non è consentito in 5.2.7.5 ed è né permesso in 5.2.7.6. La mia regolazione lo fa funzionare sotto 5.2.7.6

+0

Grazie Alex. Comunque non è una mia domanda. – Chubsdad