2014-12-01 4 views
6

Mi chiedevo se potevo usare la formattazione snprintf in un ostream in modo che potessi incorporare la chiamata a snprintf nell'espressione di flusso stessa. Questo compila in GCC 4.9, ma va bene?C++ utilizzando snprintf in ostream con buffer di rvalue, questo è ben formato?

cout << [](char (&&buf) [12], int d) { snprintf(buf, 12, "%d", d); return buf; } ({ }, 15) << endl; 
+3

Questa riga di codice deve vincere un premio per l'utilizzo di lambda. – Barry

+0

La vera domanda qui, IMO, è come '{}' si lega a un valore di un tipo di array e cosa significa che ciò avvenga. Quando rispondiamo a questa domanda, la domanda sul fatto che questo codice abbia definito o meno il comportamento avrà avuto risposta. Inoltre, hai un extra ')' vicino alla fine di quella linea. – cdhowie

+0

@cdhowie, penso che tu abbia ragione, sulla natura della domanda. Ho rimosso l'extra ')' – ThomasMcLeod

risposta

7

Questo è ben formato e ben definito. {} viene utilizzato per copiare-elenco-inizializzazione di un riferimento di rvalue a char [12], che crea una matrice temporanea char [12] a cui è associato il riferimento. Questa vita temporanea fino alla fine dell'espressione completa - in questo caso, fino al punto e virgola, quindi un puntatore a un elemento nell'array può essere restituito e utilizzato in modo sicuro per la stampa all'interno di tale espressione. (Il lambda restituisce un char * punta al primo elemento di questa matrice.)

Standardese:

§8.5 [dcl.init]/P17:

La semantica di inizializzatori sono i seguenti. [...]

  • Se l'inizializzatore è un (non tra parentesi) rinforzato-init-list, l'oggetto o riferimento è list-inizializzato (8.5.4).

§8.5.4 [dcl.init.list]/p3:

List-inizializzazione di un oggetto o di riferimento di tipo T è definito come segue:

  • [...]
  • Altrimenti, se T è un tipo di riferimento, un valore provvisorio del tipo a cui fa riferimento T è co py-list-inizializzato o elenco diretto-inizializzato, a seconda del tipo di inizializzazione per il riferimento e il riferimento è associato a tale temporaneo. [Nota : Come di consueto, il legame fallirà e il programma è malformata se il tipo di riferimento è un riferimento Ivalue un tipo non-const. - nota end ]

§12.2 [classe.temporanea]/p5:

Un temporaneo legato a un parametro di riferimento in una chiamata di funzione (5.2.2) persiste fino al completamento del full-espressione contenente la chiamata .

+0

Questa era la risposta di cui avevo bisogno, grazie. – ThomasMcLeod

3

Sono abbastanza sicuro che questo è OK. Se ho capito bene, lambda restituirà un oggetto di tipo char[12] come temporaneo (dalla deduzione del tipo di ritorno automatico). Quella temporanea può quindi essere passata in un'altra funzione, in questo caso operator<<().

Significa che potrebbero essere fatte delle copie, ma RVO potrebbe occuparsene.

UPDATE

Come notato nei commenti e nel migliore risposta fornita dal T.C., il tipo restituito dedotto da questo lambda è in realtà un char *, piuttosto che un char [12]. Ho confermato questo con il codice in GCC.

+0

Non restituisce un 'char [12]'. Restituisce un 'char *'. –

+0

confermato ... grazie! –