2010-09-30 6 views
7

In questo codice:Perché dovrei aver bisogno di una conversione?

template<class T> 
struct Side 
{ 
}; 

template<class T> 
struct LeftSide : public Side<T> 
{ 
}; 
template<class T> 
struct RightSide : public Side<T> 
{ 
}; 

Side<int>* f(int left, int right) 
{ 
    return left < right ? new LeftSide<int> : new RightSide<int>;//<---Here I'm returning either left or right side 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    return 0; 
} 

sto ottenendo un errore:
_Error 1 Errore C2446: ':': nessuna conversione da 'rightside *' a 'Leftside *' _

I' Ho pensato (erroneamente come vedo) che posso assegnare il puntatore da derivato a base senza problemi. Quindi dov'è il problema?

risposta

14

Il problema non è con la conversione da uno o LeftSideRightSide a Side<T>. Come inizialmente pensavi, questa conversione andrebbe bene.

Piuttosto, il problema è con questa espressione:

left < right ? new LeftSide<int> : new RightSide<int> 

Rompiamo questo un po '. L'operatore ternario (propriamente di cui al standard come il 'operatore di confronto') si presenta così:

bool_val ? lhs_expression : rhs_expression 

Tenete a mente che tutto questo costrutto è di per sé un'espressione. Significato restituisce un valore, che deve avere un tipo, obv. Il tipo di espressione intera viene dedotto dai tipi di lhs_expression e rhs_expression. In questo caso, hai un LeftSide e un RightSide. Quindi, ecco il tuo problema.

LeftSide e RightSide non sono direttamente correlati tra loro oltre che con una classe di base comune e non è disponibile alcuna conversione tra di essi. (Dovresti scriverne uno.) Quindi non esiste un singolo tipo di dati che lo bool_val ? lhs_expression : rhs_expression possa avere. Potresti pensare, "beh, stupido compilatore, perché non capire solo la classe base comune e usarla?" Questo è, in effetti, un po 'di dolore. Lasciando da parte il fatto che sia giusto o sbagliato, non funziona in questo modo.

Hai due opzioni.

One, utilizzare un costrutto più semplice:

if(left < right) 
    return new LeftSide<int>; 
else 
    return new RightSide<int>; 

Due, se davvero vuole veramente utilizzare l'operatore ternario (che è il caso a volte), è necessario cucchiaio-alimentare il compilatore è tipi di dati:

Side<int>* f(int left, int right) 
{ 
    return left < right ? static_cast<Side<int>*>(new LeftSide<int>) : static_cast<Side<int>*>(new RightSide<int>);// now you're good 
} 
+1

(1) Non è possibile scrivere le conversioni definite dall'utente tra i tipi di puntatore. (2) Devi solo correggere il tipo di un operando per farlo funzionare. (3) Anche 'static_cast' è eccessivo dato che esiste una conversione implicita e' static_cast' potrebbe impedire al compilatore di allertare sui legittimi problemi di sicurezza del tipo. –

4

Penso che il? : l'operatore richiede che le 2 scelte siano dello stesso tipo; Non che essi possono essere convertiti allo stesso tipo

FYI gcc non riesce lo stesso

error: conditional expression between distinct pointer types ‘LeftSide<int>*’ and ‘RightSide<int>*’ lacks a cast 

fusione sia a Side (int) * opere (ma probabilmente sapeva che già)

+2

La conversione è ok, ma un operando deve essere convertibile al tipo dell'altro. Se è consentito qualsiasi tipo, il problema diventa intrattabile nel caso generale. –

+1

Penso che tu abbia ragione ma è talmente deludente! –

2

Si desidera sia filiali per restituire un Side<int>*, ma il compilatore non lo sa, il tipo Side<int> non appare da nessuna parte in quella espressione.

Dal momento che non piace usare un cast in cui esiste una conversione implicita, mi piacerebbe scrivere questo come:

if (left < right) return new LeftSide<int>; 
return new RightSide<int>; 

Ma se si desidera utilizzare un operatore ternario,

Side<int>* i_want_this_type; 
return (left < right) ? new LeftSide<int> : (i_want_this_type = new RightSide<int>); 

Ora il ramo destro è il tipo Side<int>*, la mano sinistra è convertibile in quel tipo, tutto è ok (e il compilatore ottimizza la variabile extra).

+0

motivo per downvote? –

+0

Non avrei d/v'ed ma immagino sia perché hai introdotto un temporaneo - anche se è un temporaneo che il compilatore può ottimizzare a vapore. –

0

I due dovrebbero essere dello stesso tipo o uno dovrebbe essere convertibile all'altro.

return left < right ? (Side<int>*)new LeftSide<int> : (Side<int>*)new RightSide<int>; 
+0

Un cast in stile C è totalmente eccessivo. –

+0

E brutalmente brutto e vecchio-out-of-date-programmatore-hasbeen-hack-ish –

Problemi correlati