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
dann übergibt der Code auch clang.
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, wobeiT
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 TypM
[...], hat jeder dieser Klassen einen Kopierkonstruktor, dessen erster Parameter vom Typ istconst M&
oderconst 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.
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.
Tags und Links c++ clang c++11 templates copy-constructor