2013-02-07 19 views
6

Der folgende Code kompiliert (gcc 4.7.2 oder icc 13) und produziert "1 2" Ausgabe. Das bedeutet, dass const Qualifier gelöscht wird, d. e., f<int&> hat den Parametertyp int&.C++ 98/03 Referenzzusammenbruch und CV Qualifier

Warum passiert das? Wie ich verstehe, nach §14.3.1.4:

Wenn eine Vorlage-Argument für eine Vorlage-Parameter T Namen ein Typ „Referenz auf cv1S“, einem Versuch, den Typ „Referenz auf zu erstellen CV2T“erzeugt den Typ‚Referenz auf CV12S‘, wobei CV12 ist die Vereinigung der cv-qualifizierte ers CV1 und CV2. Redundante cv-Qualifizierer werden ignoriert.

const sollte nicht fallen gelassen werden. Hier ist der Code:

#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

Ich kann dieses Zitat in C++ 98 oder C++ 03 nicht finden. §14.3.1 ist "Template type arguments" und hat keinen Unterabschnitt oder Absatz 4. –

Antwort

4

GCC 4.7.2 tut nicht diese kompilieren, wenn das Flag -std=c++98 angegeben ist. Tatsächlich fallen in C++ 98 (sowie in C++ 03) Verweise auf Referenzen nicht zusammen.

Ein Versuch f<int&> zu instanziieren, wobei T = int&, die folgende Funktion Signatur erzeugt (hier I die Position des Argumenttypen absichtlich Schalter T und der const Spezifizierer, die wegen const T& erlaubt ist, ist die gleiche wie T const&):

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

Das oben genannte ist in C++ 98, noch in C++ 03 nicht legal. Konsequent ist dies der Fehler, den Sie von GCC 4.7.2 erhalten: Trotzdem

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&' 

, wenn Sie die -std=c++11 Flag verwenden, dann führt der Compiler Referenz kollabiert, wenn die Vorlage Instanziierung: ein L-Wert Referenz auf ein L-Wert-Referenz eine wird L-Wert-Referenz:

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

Hier ist die const Qualifier werden fallen gelassen, weil es mit der Referenz gilt, und nicht auf das referenzierte Objekt. Da Referenzen nicht neu zugeordnet werden können, sind sie const von Natur aus, weshalb die const als überflüssig und entfernt betrachtet wird. Eine Erläuterung finden Sie unter this Q&A on SO.

Dies ergibt eine lvalue-Referenz auf eine lvalue-Referenz, die in eine einfache lvalue-Referenz aufgelöst wird. Daher wird die Signatur auf der rechten Seite instanziiert.

Das obige ist ein praktikabler Kandidat, um den Anruf für f<int&>(a) aufzulösen, und daher kompiliert es ohne Fehler.

+0

Wie kann 'void f (const int & t) {t ++; } 'kompilieren? Es ändert "t", was eine konstante Referenz ist. – Kleist

+0

@Kleist: Hm, du hast recht. Lassen Sie mich untersuchen –

+0

Anstatt C++ 11 standardmäßig angenommen, der Code oben funktioniert seit einiger Zeit in gcc als Erweiterung (es kompiliert im Standardmodus in 4.1, aber schlägt fehl, wenn Sie nach -ansi fragen. –

4

Hier ist 1770, wo das Zitat in Frage zu stammen scheint:

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

14.3.1 - Vorlagentyp Argument

-4- Wenn ein Vorlage-Argument für ein template- Der Parameter T benennt einen Typ "lvalue-reference to cv1 S", ein Versuch, den Typ "(lvalue oder rvalue) reference to cv2 T" zu erzeugen, erzeugt den Typ "lvalue-reference to cv12 S", wobei cv12 die Union der Lebenslauf-Qualifikanten cv1 und cv2. Wenn das Template-Argument den Typ "rvalue-reference to cv1 S" angibt, wird beim Versuch, den Typ "lvalue-reference to cv2 T" zu erstellen, der Typ "lvalue-reference to cv12 S" erstellt. Wenn das Template-Argument einen Typ "rvalue-reference to cv1 S" nennt, erzeugt ein Versuch, den Typ "rvalue-reference to cv2 T" zu erzeugen, den Typ "rvalue-reference to cv12 S". Redundante CV-Qualifier werden ignoriert.

Hier ist 2118, wo das Zitat gestrichen wurde:

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

14.3.1 - Vorlagentyp Argument

-4- Wenn ein Vorlage-Argument für eine Vorlage -Parameter T benennt einen Typ "Verweis auf cv1 S" das ist ein Verweis auf einen Typ A, ein Versuch, den Typ "Verweis auf cv2 T" zu erstellen "lvalue-reference to cv T" erzeugt den Typ "reference to cv12 S", wobei cv12 die Union der cv-Qualifier cv1 und cv2 ist. Redundante cv-Qualifier werden ignoriert „L-Wert-Verweis auf A“, während ein Versuch, den Typ „R-Wert-Verweis auf cv T“ den Typ T. schafft zu erstellen

Was Sie zitieren scheint veraltet zu sein Wortlaut .

+0

Gute finden! .... –

+0

Hinweis: In der endgültigen Version von C + +11, dies endete in 8.3.2/5 (dh Teil des dcl.ref-Abschnitts, nicht mehr von temp.arg.type) Der Wortlaut ist abgesehen von Namen unverändert. – jogojapan