Wann werden spezielle Member-Funktionen einer Template-Klasse instanziiert?

8

Wann werden die speziellen Member-Funktionen (speziell die Konstruktoren kopieren / verschieben und Zuweisungsoperatoren kopieren / verschieben) einer Template-Klasse instanziiert? Sobald die Klasse selbst instanziiert ist oder nur wenn sie benötigt wird?

Dies kommt in der folgenden Situation vor:

%Vor%

Clang verweigert die Kompilierung dieses Codes mit den folgenden Fehlern:

%Vor%

legt nahe, dass es versucht, den Kopierkonstruktor zu instanziieren, sobald die Klasse instanziiert wird.

GCC jedoch kompiliert den Code gut, was darauf hindeutet, dass er nur versucht, den Kopierkonstruktor zu instantiieren, wenn er tatsächlich benötigt wird.

Welches Verhalten des Compilers ist korrekt?

(Eine ähnliche Diskrepanz wird für Zuweisungsoperatoren angezeigt.)

UPDATE : Das hat etwas damit zu tun, dass der Kopierkonstruktor von pair in diesem Beispiel default ed ist, weil ich seine Definition in

ändere %Vor%

dann übergibt der Code auch clang.

    
HighCommander4 29.04.2012, 08:16
quelle

2 Antworten

2

Die relevante Passage des Standards ist [dcl.fct.def.default] / 1:

  

Eine Funktion, die explizit voreingestellt ist, muss   [...]   haben den gleichen deklarierten Funktionstyp (mit Ausnahme von möglicherweise abweichenden ref-Qualifikationsmerkmalen und außer dass im Falle eines Kopierkonstruktors oder Kopierzuweisungsoperators der Parametertyp "Verweis auf nicht-const T " sein kann, wobei T ist der Name der Klasse der Memberfunktion), als wäre sie implizit deklariert worden

Diese Regel gilt auch dann, wenn die Standardfunktion nicht verwendet wird. Nun sagt [class.copy] / 9:

  

Der implizit deklarierte Kopierkonstruktor hat die Form

     

X::X(const X&)

     

Wenn [...] für alle nicht statischen Datenelemente von X vom Typ M [...], hat jeder dieser Klassen einen Kopierkonstruktor, dessen erster Parameter vom Typ ist const M& oder const volatile M& .

     

Andernfalls hat der implizit deklarierte Kopierkonstruktor die Form

     

X::X(X&)

Daher ist ein Beispiel wie dieses schlecht geformt (und sollte die Diagnose, die Sie sehen) erzeugen:

%Vor%

In Ihrem Beispiel gilt diese Regel jedoch nicht. Aufgrund eines Clang-Bugs (der bereits behoben ist) wurden gelöschte Kopierkonstruktoren fälschlicherweise als nicht konstante Parametertypen betrachtet, was zu diesem Fehler führte.

    
Richard Smith 29.04.2012, 21:45
quelle
5

Sehen Sie sich Abschnitt 14.7.1 des aktuellen C ++ 11 Standards an. Um aus der n3242-Version des Entwurfs zu zitieren:

  

Die implizite Instantiierung einer Klassenvorlagenspezialisierung verursacht   die implizite Instantiierung der Deklarationen, nicht aber der   Definitionen oder Standardargumente der Klassenmemberfunktionen,   Mitgliedsklassen, statische Datenmitglieder und Mitgliedervorlagen; und es   verursacht die implizite Instantiierung der Definitionen von member   anonyme Gewerkschaften. Es sei denn, ein Mitglied einer Klassenvorlage oder ein Mitglied   Vorlage wurde explizit instanziiert oder explizit spezialisiert,   Die Spezialisierung des Members wird implizit instanziiert, wenn der   Spezialisierung wird in einem Kontext referenziert, der das Mitglied erfordert   Definition zu existieren; insbesondere die Initialisierung (und alle anderen   assoziierte Nebenwirkungen) eines statischen Datenelements tritt nur dann auf, wenn   Das statische Datenelement selbst wird in einer Weise verwendet, die das erfordert   Definition des statischen Datenelements, das existiert.

Das heißt also, wenn Sie eine Klasse als Typ wie oben verwenden, werden nur die Deklarationen damit instanziiert. Daher sollte die tatsächliche (voreingestellte) Implementierung des Kopierkonstruktors nicht instanziiert werden, da sie im obigen Code nicht benötigt wird. Also behandelt GCC das richtig, Clang dagegen nicht.

Auch Ihre Bearbeitung legt nahe, dass Clang die Implementierung für den Standard-Kopierkonstruktor zu früh generiert, da Ihr direkt implementierter Kopierkonstruktor ebenfalls fehlerhaft ist (Sie können den Kopierkonstruktor nicht für S aufrufen, wie Sie es in Ihrem eigenen tun Implementierung). Da die vorgegebene Implementierung und Ihre Implementierung in jeder Hinsicht die gleiche sein sollten (einschließlich der Instanziierungszeit), würde ich dies als einen klingenden Bug betrachten.

    
LiKao 29.04.2012 09:08
quelle