Ich habe die Hälfte an diesem Stück Code gearbeitet und dachte, dass das offensichtlich nicht kompiliert wird, bevor ich den Build-Knopf drücke. Ich war überrascht, dass es nicht nur kompiliert, sondern auch verlinkt und gearbeitet hat.
Wenn ich raten würde, würde ich sagen, dass SFINAE dafür verantwortlich ist, das zu kompilieren ... oder?
%Vor%BEARBEITEN : Ich benutze Visual-C ++ 2008, vielleicht ist es eine seltsame Eigenart von VS
Der Code ist nicht legal.
i = j
ruft den implizit definierten Kopierzuweisungsoperator in MyClass
auf. Diese Funktion ruft den Kopierzuweisungsoperator für jedes seiner Unterobjekte auf, einschließlich der direkten Basisklassen [class.copy 12.8 p28].
Wenn Sie dem Kopierzuweisungsoperator für BaseClass Code hinzufügen, können Sie sehen, wo VS falsch läuft:
%Vor% Bei mir wird "struct MyClass" ausgedruckt. VS ist der BaseClass
Kopie Zuweisungsoperator aufrufe, indem Sie die Parameter übergeben erhielten in MyClass:operator=
direkt, und nicht nur das BaseClass
Unterobjekt von j.
SFINAE kommt nicht ins Spiel, weil die Template-Funktionen nicht fehlschlagen. VS generiert den impliziten Kopierzuweisungsoperator einfach falsch.
Um es zusammenzufassen: VS generiert den impliziten Kopierzuweisungsoperator als
%Vor%Wenn es sein sollte:
%Vor% Im Dunkeln geschossen: Der Compiler instanziiert die Basisklasse ' operator =
mit T
= MyClass
. Ich weiß jetzt, ob das legal oder sogar erforderlich ist, aber es macht einen gewissen Sinn: Der automatisch generierte Code für operator =
sieht im Wesentlichen so aus (na ja, Pseudocode):
Nun stellt der Compiler fest, dass BaseClass::operator =<MyClass>(MyClass const&)
die beste Übereinstimmung ist und instanziiert.
Nun, da es BaseClass::operator=(const BaseClass&)
nicht aufrufen kann (von der standardmäßig generierten MyClass::operator=
für das, was es wert ist), weil es privat ist, ruft es nur template<typename T> BaseClass::operator(const T &)
mit T=BaseClass
auf. Es gibt also keinen Aufruf für eine nicht definierte Funktion.
Ich schätze, die Situation wäre anders, wenn die anderen öffentlich wären. In diesem Fall würde der Compiler diese über die Vorlage bevorzugen, aber da er sie nicht sehen kann, wenn sie privat sind, passen die Template-Versionen genauso gut.
Der Compiler generiert automatisch einen (Standard) Kopierkonstruktor für MyClass
, da ein solcher nicht definiert ist. Wenn Sie den Typ i
und j
von MyClass
auf BaseClass
ändern, sehen Sie den erwarteten Fehler, da der Compiler dann versucht, den privaten, nicht implementierten Zuweisungsoperator zu binden.
Wenn wir mit MSVC 2010 Ultimate SP1 etwas tiefer gehen, können wir den genauen Grund sehen:
%Vor% Der Zuweisungsoperator wird für MyClass
by BaseClass::=<T>
unter Verwendung von MyClass
als Typ durch MyClass
es Standardkopieoperator aufgerufen, ob dies ein Fehler ist oder ein MSVC-ism an MS und den C ++ - Standard liegt zu entscheiden.
MyClass
verwendet einen implizit definierten Kopierzuweisungsoperator, da es keine vom Benutzer deklarierte Version gibt. Gemäß dem Standard führt diese implizite Kopierzuordnung Folgendes aus (C ++ 03 12.8 / 13 "Kopieren von Klassenobjekten"):
Beachten Sie, dass der Standard in 12.8 / 9 einen benutzerdeklarierten Kopierzuweisungsoperator als "nicht statische Nicht-Template -Memberfunktion der Klasse X mit genau einem Parameter des Typs X, X & amp; , const X & amp;, flüchtig X & amp; oder const flüchtig X & amp; (Betonung meiner).
Also nach dem Standard, die Template-Funktion
%Vor% Sollte nicht vom Operator für die implizite Kopienzuordnung MyClass
aufgerufen werden. MSVC handelt hier nicht standardgemäß. GCC diagnostiziert dies zu Recht: