2012-11-11 21 views
10

Stavo passando un po 'di codice in CodeProject e ho trovato il seguente codice per il cast di C++.Implementazione di C++ Cast

template <class OutputClass, class InputClass> 
union horrible_union{ 
    OutputClass out; 
    InputClass in; 
}; 
template <class OutputClass, class InputClass> 
inline OutputClass horrible_cast(const InputClass input){ 
    horrible_union<OutputClass, InputClass> u; 
    u.in = input; 
    return u.out; 
} 

Perché il cast ha implementato il modo sopra descritto. Perché non possiamo semplicemente fare un cast manuale. Qualcuno può dare un esempio di quando un cast normale non funzionerebbe?

+4

L'accesso a un membro di un'unione dopo aver impostato un membro diverso è un comportamento non definito, quindi tutto è meglio di questo approccio "orribile_union". –

+0

Probabilmente è per questo che si chiama cast orribile. Questo è fondamentalmente per implementare alcuni comportamenti specifici del compilatore. – KodeWarrior

risposta

9

Questo approccio consente in sostanza di superare qualsiasi cast, anche se si basa su un comportamento non definito.

Un cast normale si lamenterebbe quando si esegue il cast tra tipi non correlati, mentre questo non lo farebbe.

struct A{}; 
struct B{}; 

template <class OutputClass, class InputClass> 
union horrible_union{ 
    OutputClass out; 
    InputClass in; 
}; 
template <class OutputClass, class InputClass> 
inline OutputClass horrible_cast(const InputClass input){ 
    horrible_union<OutputClass, InputClass> u; 
    u.in = input; 
    return u.out; 
} 

int main() 
{ 
    A a; 
    B b; 
    a = horrible_cast<A,B>(b); //this compiles 
    a = reinterpret_cast<A>(b); //this doesn't 
} 

Bottom line: è orribile, non farlo.

+1

Se si sta lavorando su una particolare architettura e si utilizza un particolare compilatore (per alcuni sistemi embedded), potrebbe essere un approccio valido per eseguire conversioni di tipo che abbiano senso solo su tale architettura. Ma è ancora pericoloso, sono d'accordo. – bitmask

2

L'utilizzo di un'unione in questo modo è in genere equivalente a una punta di puntatori reinterpret_cast. Tuttavia, questo non copia gli oggetti, il tuo esempio lo fa (due volte anche con RVO, infatti, sarebbe piuttosto più efficiente avere const InputClass& input come argomento). In questo modo puoi operare direttamente sul suo risultato senza eventualmente modificare l'oggetto originale.

Che cosa è esattamente utile per ... hm. Non penso che ci sia davvero un buon caso d'uso, i cast non controllati dovrebbero sempre essere evitati, e come ha osservato David Hammen, questo è in realtà completamente indefinito (anche se normalmente funzionerà, se usato "correttamente").

+0

Forse il loro negozio ha una politica contro 'reinterpret_cast', ma non questa scappatoia. – Barmar

+0

In tal caso sarebbe ancora più orribile usarlo: 'reinterpret_cast' è pericoloso, ma questo è peggio. – leftaroundabout

+0

Personalmente preferirei vedere "reinterpret_cast" (e forse dover andare dopo una rinuncia se c'è una regola contro di essa) che nascondere il cast in questo modo. –