Una caratteristica di std::stringstream
è che si prevede che se il flusso è usato come un bool
, esso viene convertito in true
se il flusso è ancora valido e false
se non lo è. Ad esempio questo consente di utilizzare una sintassi semplice se si implementa la propria versione di cast lessicale.
(Per riferimento, boost
contiene una funzione template chiamato lexical_cast
che fa qualcosa di simile al seguente funzione template semplice.)
template <typename T, typename U>
T lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
throw bad_lexical_cast();
}
}
Se, per esempio, si lavora su un progetto in cui non sono consentite eccezioni, si potrebbe vuoi invece lanciare la seguente versione di questo.
template <typename T, typename U>
boost::optional<T> lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
return boost::none;
}
}
(Ci sono vari modi sopra potrebbero essere migliorati, questo codice è solo per fare un esempio.)
Il operator void *
viene utilizzato in quanto sopra come segue:
ss << u
restituisce un riferimento a ss
.
- Il
ss
viene convertito in modo implicito in void *
che è nullptr
se l'operazione di flusso non è riuscita e non null se il flusso è ancora buono.
- L'operatore
&&
si interrompe rapidamente, a seconda del valore di verità di quel puntatore.
- La seconda parte
ss >> t
viene eseguita e restituisce e viene anche convertita in void *
.
- Se entrambe le operazioni sono riuscite, è possibile restituire il risultato in streaming
t
. Se uno dei due fallisce, segnaliamo un errore.
La funzione di conversione bool è fondamentalmente solo zucchero sintattico che consente di scrivere in modo conciso questa (e molte altre cose).
L'inconveniente di introdurre effettivamente una conversione bool implicita è che poi, std::stringstream
diventa conversione implicita int
e molti altri tipi anche perché è bool
conversione implicita int
. Questo alla fine provoca incubi sintattici altrove.
Per esempio, se std::stringstream
avuto un operator bool
conversione implicita, si supponga di avere questo semplice codice: (!)
std::stringstream ss;
int x = 5;
ss << x;
Ora nella risoluzione di sovraccarico, si hanno due potenziali sovraccarichi da considerare, quella normale operator<<(std::stringstream &, int)
, e quello in cui ss
viene convertito in bool
, poi promosso int
, e l'operatore bit di spostamento può applicare operator<<(int, int)
, tutto a causa della conversione implicita a bool
...
La soluzione alternativa consiste nell'utilizzare una conversione implicita in void *
, che può essere utilizzata contestualmente come bool, ma non è in realtà implicitamente convertibile in bool o int.
In C++ 11 non abbiamo più bisogno di questa soluzione alternativa, e non c'è ragione per cui qualcuno avrebbe esplicitamente utilizzato la conversione void *
, quindi è stata appena rimossa.
(Sto cercando un riferimento, ma credo che il valore di questa funzione sia stato specificato solo quando dovrebbe essere nullptr
rispetto a quando non dovrebbe essere nullptr
e che è stata definita l'implementazione di quel puntatore diverso da zero Valori potrebbe cedere. Quindi, qualsiasi codice che si basava sulla versione void *
e non può essere banalmente riscritta per utilizzare la versione bool
sarebbe stata corretta in ogni modo.)
il void *
soluzione non è ancora senza problemi. In boost è stato sviluppato un linguaggio più sofisticato di "safe bool" per il codice pre-C++ 11, che è basato su qualcosa come T*
dove T
è un "tipo usato una volta", come una struttura definita nella classe implementare l'idioma, o usare una funzione pointer-to-member per quella classe e usare i valori di ritorno che sono o una particolare funzione di membro privato di quella classe, o nullptr. L'idioma "safe bool" è usato ad esempio in tutti gli indicatori intelligenti di boost.
Indipendentemente da questo intero problema è stato ripulito in C++ 11 introducendo explicit operator bool
.
Maggiori informazioni qui: Is the safe-bool idiom obsolete in C++11?
fwiw Penso che questi programmi non siano "validi", semplicemente capita di compilare. ma sicuramente danno un comportamento indefinito. –
Questo potrebbe interessarti: http://www.artima.com/cppsource/safeboolP.html – moooeeeep
@moooeeeep: sì, è sicuramente un post interessante. Grazie per il link, – Destructor