2015-08-27 17 views
9

Esistono regole per la conversione del tipo implicito per gli argomenti dell'operatore ternario?C++: Operatore ternario (operatore condizionale) e le sue regole di conversione di tipo implicito

L'operatore ternario deve sempre restituire lo stesso tipo. Questo tipo è determinato esclusivamente dal secondo e dal terzo argomento (1st ? 2nd : 3rd), pertanto entrambi gli argomenti vengono convertiti in questo tipo. Come viene determinato questo tipo?

Per essere più precisi, ho testato un esempio:

class pointclass 
{ 
    pointclass(); 

    pointclass(int i); // (pointclass)(int) 
    operator bool() const; // (bool)(pointclass) 
}; 

Ho una classe (pointclass), che consente la conversione implicita da int a pointclass e conversione implicita da pointclass a bool.

int i; 
pointclass p; 
bool b; 

b ? p : i; // (bool) ? (int)(bool)(pointclass) : (int) 
b ? i : p; // (bool) ? (int) : (int)(bool)(pointclass) 

Utilizzando l'operatore ternario, metto a confronto pointclass e int. Il compilatore utilizza la conversione implicita da pointclass a bool e quindi la conversione standard da bool a int. Questo è fatto, non importa se scambio gli argomenti 2 ° e 3 °. Perché non converte int in pointclass?

Utilizzando un operatore di confronto è molto più semplice:

p == i;  // (pointclass) == (pointclass)(int) 
i == p;  // (int) == (int)(bool)(pointclass) 

Il tipo degli argomenti è semplicemente determinato dal primo argomento.

Ma non capisco le regole di conversione del tipo dell'operatore ternario. Per me sembra proprio come usare la maggior parte delle conversioni.

+0

Sì, le regole sono in [expr.cond] nello standard. – chris

+0

Qualcuno più esperto in modi standard di me può dare una risposta autoritaria, ma come regola empirica, si convertono al tipo comune "più vicino" in cui possono essere convertiti. – SergeyA

+0

Se pensi che il C++ faccia cose strane, risparmi un pensiero per i poveri ragazzi di Java. – Bathsheba

risposta

6

Citando MSDN:

espressioni condizionali hanno associatività da destra a sinistra. Il primo operando deve essere di tipo integrale o puntatore. Le seguenti regole si applicano al secondo e al terzo operando:

Se entrambi gli operandi sono dello stesso tipo, il risultato è di quel tipo.

Se entrambi gli operandi sono di tipo aritmetico o di enumerazione, le normali conversioni aritmetiche (trattate in Conversioni aritmetiche) sono eseguite su per convertirle in un tipo comune.

Se entrambi gli operandi sono di tipo puntatore o se uno è un tipo di puntatore e l'altro è un'espressione costante che restituisce 0, puntatore conversioni vengono eseguite per convertirli in un tipo comune.

Se entrambi gli operandi sono di tipo di riferimento, vengono eseguite conversioni di riferimento per convertirli in un tipo comune.

Se entrambi gli operandi sono di tipo nullo, il tipo comune è di tipo nullo.

Se entrambi gli operandi sono dello stesso tipo definito dall'utente, il tipo comune è quel tipo.

Se gli operandi hanno tipi diversi e almeno uno degli operandi ha un tipo definito dall'utente, le regole della lingua vengono utilizzate per determinare il tipo comune. (Vedere l'avvertenza sotto)

Fondamentalmente ciò che accade è che il compilatore C++ cerca il tipo comune per il secondo e il terzo operando. Se riesce a trovarlo, questo è il tipo di risultato. Se non riesce a trovarlo, si traduce in un errore di tempo di compilazione.

Se si desidera visualizzare la posizione standard, è possibile vedere le regole in working draft for newest standard, 5.16 (pagina 129).

Come non convertire int in pointclass - la regola generale è che si sempre andare giù per la gerarchia, non su - immaginare una gerarchia di classi più avanzata; da qualche parte lassù ci potrebbero essere decine di modi per convertire entrambi i tipi in un'altra classe, ma è proprio quello che vuoi? Inoltre, determinare quale classe usare potrebbe essere impossibile. Pertanto, abbiamo downcast.

+0

Grazie per questa risposta. Ho capito, un operatore condizionale converte sempre verso il basso una gerarchia, in cui un tipo standard è inferiore a una classe. Un problema nasce dalle conversioni implicite tra questi tipi standard. Potrei evitare quelle conversioni definendo esplicitamente operatori di conversione (impliciti) tra 'pointclass' e tutti i tipi standard eccetto' bool' come 'protected'. Grazie! – dib