2013-02-07 8 views
6

Il codice seguente compila (gcc 4.7.2 o icc 13) e produce l'uscita "1 2". Il che significa che il qualificatore const viene eliminato, i. e., f<int&> ha il tipo di parametro int&.C++ 98/03 riferimenti di collassamento e qualifiche cv

Perché succede? Mi pare di capire, in base alle §14.3.1.4:

Se un modello-argomento per un modello di parametri T nomi tipo “riferimento alla CV1S”, un tentativo di creare il tipo di “riferimento alla CV2T”crea il tipo di‘riferimento alla CV12S’, dove CV12 è l'unione delle fi catori cv-quali CV1 e cv2. I cv-quali fi chi ridondanti sono ignorati.

const non deve essere eliminato. Ecco il codice:

#include <iostream> 
using namespace std; 

template <typename T> 
void f(const T& t) 
{ 
    t++; 
} 

int main() 
{ 
    int a = 1; 

    cout << a; 
    f<int&>(a); 
    cout << ' ' << a << endl; 

    return 0; 
} 
+4

Non riesco a trovare quella citazione in C++ 98 o C++ 03. §14.3.1 è "Argomenti tipo di modello" e non ha alcuna sottosezione o paragrafo 4. –

risposta

4

GCC 4.7.2 fa non compilare questo quando viene specificato il flag -std=c++98. Infatti, in C++ 98 (così come in C++ 03) i riferimenti ai riferimenti non collassano.

Un tentativo di un'istanza f<int&>, dove T = int&, produce il seguente identificativo funzione (qui a passare intenzionalmente la posizione del tipo di argomento T e const specificatore, che è consentito perché const T& è uguale T const&):

void f(int& const& t) // ERROR: reference to reference is illegal 

Quanto sopra non è legale in C++ 98, né in C++ 03. Coerentemente, questo è l'errore che si ottiene da GCC 4.7.2:

Compilation finished with errors: 
source.cpp: In function 'int main()': 
source.cpp:15:14: error: no matching function for call to 'f(int&)' 
source.cpp:15:14: note: candidate is: 
source.cpp:5:6: note: template<class T> void f(const T&) 
source.cpp:5:6: note: template argument deduction/substitution failed: 
source.cpp: In substitution of 'template<class T> void f(const T&) [with T = int&]': 
source.cpp:15:14: required from here 
source.cpp:5:6: error: forming reference to reference type 'int&' 

Tuttavia, se si utilizza il flag -std=c++11, il compilatore esegue riferimento collasso quando si crea un'istanza del modello: un riferimento lvalue ad un riferimento lvalue diventa un di riferimento lvalue:

void f(int& const& t) == void f(int& t) 

Qui la qualificazione const viene scartato, perché si applica al riferimento, e non l'oggetto di riferimento. Poiché i riferimenti non possono essere riassegnati, sono di natura const, motivo per cui lo const è considerato superfluo e rimosso. Vedi this Q&A on SO per una spiegazione.

Ciò produce un riferimento di lvalue a un riferimento di lvalue, che si risolve in un semplice riferimento di lvalue. Quindi, la firma sul lato destro è istanziata.

Quanto sopra è un candidato valido per risolvere la chiamata per f<int&>(a) e, pertanto, viene compilato senza errori.

+0

Come si può 'void f (const int & t) {t ++; } 'Compila? Modifica 't' che è un riferimento const. – Kleist

+0

@Kleist: Hm, hai ragione. Lasciatemi indagare su –

+0

Invece di assumere C++ 11 per impostazione predefinita, il codice sopra ha funzionato per qualche tempo in gcc come estensione (compila nella modalità predefinita in 4.1, ma fallisce se chiedi '-ansi'. –

4

Ecco 1770 in cui la citazione in questione sembra provenire:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html

14.3.1 - modello di argomenti di tipo

-4- Se un modello-argomento per una template- il parametro T assegna un tipo "lvalue-reference a cv1 S", un tentativo di creare il tipo "(lvalue o rvalue) riferimento a cv2 T" crea il tipo "lvalue-reference a cv12 S", dove cv12 è l'unione del qualificati cv1 cv1 e cv2. Se l'argomento template nomina un tipo "rvalue-reference in cv1 S", un tentativo di creare il tipo "lvalue-reference in cv2 T" crea il tipo "lvalue-reference in cv12 S." Se l'argomento template nomina un tipo "rvalue-reference in cv1 S", un tentativo di creare il tipo "rvalue-reference in cv2 T" crea il tipo "rvalue-reference in cv12 S." I qualificatori di cv ridondanti sono ignorati.

Qui è 2118 in cui la citazione è stato colpito fuori:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html

14.3.1 - tipo di modello argomenti

-4- Se un modello-argomento per un modello -parametro T identifica un tipo "riferimento a cv1 S" che è un riferimento a un tipo A, un tentativo di creare il tipo "riferimento a cv2 T" "lvalue-reference to cv T" crea il tipo "riferimento a cv12 S", dove cv12 è l'unione dei qualificatori cv cv1 e cv2. Ridondanti CV-qualificazioni vengono ignorati "lvalue-riferimento ad una", mentre un tentativo di creare il tipo di "rvalue-riferimento alla cv T" crea il tipo T.

Quello che stai citando sembra essere formulazione obsoleta .

+0

Buona scoperta! .... –

+0

Nota: nella versione finale di C + +11, questo è finito in 8.3.2/5 (cioè parte della sezione dcl.ref, non più di temp.arg.type). Il testo è invariato a parte i nomi. – jogojapan