2013-03-23 9 views
12

Ho provato il seguente codice con GCC, Clang, ICC e VS:È possibile che un riferimento di rval leghi a una funzione?

void f() {} 

void g(void (&&)()) { } 

int main() { 
    g(f); 
} 

Come possiamo vedere, g prende un riferimento rvalue ma f è un lvalue e, in generale, i riferimenti rvalue non possono essere tenuti a lvalue . Questo è esattamente ciò ICC lamenta su:

error: an rvalue reference cannot be bound to an lvalue 

VS dà anche un errore, ma per un altro motivo:

error C2664: 'void h(void (__cdecl &&)(void))' : cannot convert parameter 1 from 'void (__cdecl *)(void)' to 'void (__cdecl &&)(void)' 

Questo mi fa pensare che VS è immediatamente eseguendo un puntatore a funzione a conversione piuttosto che legare direttamente il riferimento a f. Vale la pena ricordare che se sostituisco g(f) con g(&f), i quattro compilatori producono lo stesso errore.

Infine, GCC e Clang accettano il codice e credo che siano corretti. Mio ragionamento si riferiscono al 8.5.3/5

Un riferimento di tipo “CV1 T1” viene inizializzato da un'espressione di tipo “cv2 T2” come

- Se il riferimento è un riferimento Ivalue [. ..]

- Altrimenti, [...] il riferimento deve essere un riferimento di valore.

        - Se l'espressione inizializzatore è una [...] funzione Ivalue [...]

        quindi il riferimento è legato al valore della espressione inizializzatore [...]

La mia interpretazione è corretta (che è, Clang e GCC sono conformi per il motivo dato)?

risposta

9

La mia interpretazione è corretta [...]?

Sì.

La tua interpretazione è corretta a causa del Paragrafo dello standard che hai citato. Un'ulteriore conferma viene dal punto 13.3.3.1.4/3 sul riferimento vincolante:

Eccetto per un parametro oggetto implicito, per cui vedi 13.3.1, una sequenza di conversione standard può non essere formed se richiede un legame lvalue riferimento diverso da un riferimento a un tipo const non volatile a un valore o un riferimento rvalore a un lvalue diverso da una funzione lvalue. [...]

Paragrafo 13.3.3.2/3 contiene un ulteriore (indiretto) conferma:

[...] standard sequenza di conversione S1 è una migliore sequenza di conversione di sequenza di conversione standard S2 se

- [...]

- S1 e S2 sono bind di riferimento (8.5.3) e S1 lega un riferimento a una funzione lvalue Ivalue e S2 lega un riferimento a una funzione rvalue Ivalue. [Esempio:

int f(void(&)()); // #1 
int f(void(&&)()); // #2 
void g(); 
int i1 = f(g); // calls #1 

- fine esempio]

+0

effetti. Ho provato che prima e tutti e quattro i compilatori sono conformi. –

+0

@CassioNeri: OK, grazie per aver condiviso le informazioni –