2015-01-21 11 views
13

Perché è possibile trasmettere un std::ostream a un puntatore void? Non sono a conoscenza di alcun operatore di conversione di questo tipo in std::ostream. Codice qui sottoperché std :: cout convertible to void * se si utilizza g ++?

#include <iostream> 

int main() 
{ 
    void *p = std::cout; // why does this work? 
} 

Sto chiedendo a questa domanda da quando ho visto un operatore di posizionamento new invocato come

Foo* pFoo = new (std::cerr) Foo; 

e non hanno assolutamente idea del perché si potrebbe scrivere una cosa del genere.

PS: Sto compilando con g ++ 4.9.2 con o senza -std=c++11. clang ++ non accetta il codice.

PSS: Abbiamo scoperto che a causa del cosiddetto "problema bool sicuro" (vedi @ risposta di nicebyte), in pre C++ 11 un operatore void* conversione è stato definito per std::ostream, che è stato poi rimosso in C++ 11 . Tuttavia, il mio codice si compila bene in C++ 11 usando g ++. Più di questo, clang ++ lo rifiuta non importa quale versione dello standard io uso, anche con -std=c++98, anche se la mia comprensione è che dovrebbe accettare se compilato come pre-C++ 11.

+0

'nuovo (std :: cerr) Foo'? Che cosa. Il. Inferno. – Quentin

+0

@Quentin :) questo è quello che ho detto a me stesso quando l'ho visto. – vsoftco

+1

Mi piacerebbe se potessi fornire la fonte. Posso solo pensare alle cose orribili che questo potrebbe portare a. – Quentin

risposta

11

Leggi this (la risposta alla tua domanda nell'ultima sezione "Il problema di sicurezza").

Elaborare un po ', l'attuazione definisce una conversione implicita per void* definito per cose come std::cin e std::cout, solo in modo che il codice come while(std::cin>>x){...} compilazioni, mentre il codice come int x = std::cin; non lo fa. È ancora problematico perché puoi scrivere cose come nel tuo esempio.

C++ 11 risolve questo problema introducendo conversioni esplicite.

Un operatore conversione esplicita si presenta così:

struct A { 
explicit operator B() { ... } // explicit conversion to B 
}; 

Quando A ha una conversione esplicita a B, il codice come questo diventa legale:

A a; 
B b(a); 

Tuttavia, il codice come questo non è:

A a; 
B b = a; 

Un costrutto come if(std::cin) richiede cin per essere convertito in bool, lo standard indica che, affinché la conversione sia valida in quel caso particolare, il codice come bool x(std::cin); dovrebbe essere "legale". Che può essere ottenuto aggiungendo una conversione esplicita a bool. Consente a cin/cout di essere utilizzato nel contesto precedente, evitando cose come int x = std::cout;.

Per ulteriori informazioni, fare riferimento a Bjarne's page e this question.

+1

Attenzione che questo non funziona più da C++ 11 ... –

+0

Ho modificato la mia risposta per fornire maggiori dettagli (e anche le informazioni su C++ 11). – nicebyte

+1

@nicebyte, grazie, era a conoscenza degli operatori espliciti, ma non sapeva che esiste un operatore di conversione 'void *' per 'std :: ostream'. Tuttavia, in C++ 11 sembra che questa conversione "void *" sia stata eliminata, a causa dell'introduzione della conversione esplicita a 'bool'. Comunque il mio codice funziona ancora anche con '-std = C++ 11' in' g ++ ', quindi credo che sia un difetto nell'implementazione di libstdC++. In clang ++, anche se uso '-std = C++ 98', il codice non viene ancora compilato. – vsoftco

2

Penso che sia per consentire if (std::cout) ... senza consentire la conversione implicita a bool, o qualcosa del genere.

+0

Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti da un autore, lascia un commento sotto il loro post. –

+0

@ A.L: che diamine? – Mehrdad

+0

IIRC, questa risposta è stata visualizzata nella coda * post di bassa qualità * recensione. L'ho classificato come * non una risposta * a causa dell'uso di * Penso * e * qualcosa del genere *, per me sembrava un commento, non una risposta. Ma non conosco il C++, mi dispiace se questa è una risposta valida e se è stato un errore segnalarlo. –

4

Rispondere solo al follow-up, poiché la risposta di nicebyte è perfetta per la domanda originale.

È probabile che il tuo gcc sia impostato per utilizzare libstdC++ (che non ha ancora cambiato l'operatore in quanto si tratta di una modifica di ABI), e il tuo clang è impostato per utilizzare libC++ (che era dall'inizio destinato come libreria standard C++ 11 e non è abbastanza conforme in modalità C++ 98 - fornisce un operatore di conversione bool che è esplicito in C++ 11).

+1

Ok, ha senso, grazie per aver chiarito. – vsoftco