2015-09-03 21 views
5

Considerare:Nullptr in operatore ternario

struct A { bool operator==(const A& that) { return true; } }; 
boost::optional<A&> f() 
{ 
    std::vector<A> vec; 
    auto it = std::find(vec.begin(), vec.end(), A()); 

    // Version A 
    return (it == vec.end() ? nullptr : *it); 

    // Version B 
    if (it == vec.end()) { 
     return nullptr; 
    } else { 
     return *it; 
    } 
} 

Perché versione A si compila (errore C2446: ':': nessuna conversione da 'A' a 'nullptr') mentre la versione B fa?

(so che posso fare per esempio

return (it == vec.end() ? boost::optional<A&>() : *it); 

, la mia domanda è: perché è la costruzione da nullptr apparentemente trattato diversamente da con l'operatore ternario?)

Solo testato su msvc12 (= visiva Studio 2013).

+0

In realtà [nessuno dei 'boost :: opzionale'] (http://www.boost.org/doc/libs/1_59_0/libs/optional/doc/html/optional/reference/header__boost_optional_optional_hpp_.html#boost_optional. reference.header__boost_optional_optional_hpp_.header_optional_optional) i costruttori prendono un 'nullptr', provano con' none_t'. –

+2

Lo so, eppure la mia 'versione B' compila - la mia domanda è: perché? – Roel

+1

Anche quando si arriva a "lavoro", non funziona. Restituzione di un riferimento (possibile) a una voce in un array locale? Non funzionerà molto bene davvero. Inoltre, un riferimento a un oggetto non puntatore non può mai essere un puntatore nullo. –

risposta

7

Regole per operatore ternario dallo standard 5,16

se il secondo e terzo operando con tipi diversi e deve o (possibilmente cv-qualificato) tipo di classe, o se entrambi sono glvalues ​​della categoria stesso valore e lo stesso tipo eccetto per qualifica cv, viene fatto un tentativo per convertire ciascuno di questi operandi al tipo di altro .

...

Altrimenti (se E1 o E2 ha un tipo non-classe, o se entrambi hanno tipologie di classi ma le classi sottostanti non sono le stesse e non è una classe base dell'altro): E1 può essere convertito per corrispondere a E2 se E1 può essere convertito implicitamente al tipo che E2 avrebbe dopo aver applicato lvalue-to -valval (4.1), array-to-pointer (4.2) e function-to -pointer (4.3) conversioni standard.

A non è implicitamente convertibile in nullptr e nullptr non è implicitamente convertibile in A.

La seconda versione è compilata, poiché è presente una conversione implicita da nullptr a optional.

+0

Esatto, dopo la prima modifica aveva senso, quando aggiungo un costruttore A (void *) {}, lo compila (non lo farò comunque, non preoccuparti). Grazie. – Roel