Mit diesem Code:
%Vor%g ++ Version 4.8.3 beschwert sich über einen Fehler:
%Vor%aber clang 3.5.0 kompiliert diesen Code ohne Fehler. Welches ist korrekt? Ist das ein Compilerfehler?
Mein Versuch, dies zu lösen:
Aus dem C ++ 03 Standard Abschnitt 9.5 Absatz 1:
In einer Union kann höchstens einer der Datenmitglieder jederzeit aktiv sein, das heißt, der Wert von höchstens einem der Datenmitglieder kann jederzeit in einer Vereinigung gespeichert werden. [Anmerkung: Eine spezielle Garantie wird gemacht, um die Verwendung von Vereinigungen zu vereinfachen: Wenn eine POD-Union mehrere POD-Strukturen enthält, die eine gemeinsame Anfangssequenz teilen (9.2), und wenn ein Objekt dieses POD-Union-Typs eines enthält die POD-Strukturen, ist es erlaubt, die gemeinsame Anfangssequenz eines beliebigen POD-Strukturelements zu überprüfen; siehe 9.2. ] Die Größe einer Union reicht aus, um die größten Datenmitglieder zu enthalten. Jedes Datenelement wird so zugeordnet, als wäre es das einzige Mitglied einer Struktur. Eine Union kann Memberfunktionen (einschließlich Konstruktoren und Destruktoren), jedoch keine virtuellen Funktionen (10.3) enthalten. Eine Gewerkschaft darf keine Basisklassen haben. Eine Gewerkschaft darf nicht als Basisklasse verwendet werden. Ein Objekt einer Klasse mit einem nicht-trivialen Konstruktor (12.1), einem nicht-trivialen Kopienkonstruktor (12.8), einem nicht-trivialen Destruktor (12.4) oder einem nicht trivialen Kopienzuweisungsoperator (13.5.3, 12.8) kann kein Mitglied einer Vereinigung sein, noch kann eine Reihe solcher Objekte sein. Wenn eine Union ein statisches Datenelement oder ein Element des Verweistyps enthält, ist das Programm schlecht formatiert.
Aus dem C ++ 03-Standardabschnitt 12.8 Absätze 10 und 11:
Wenn die Klassendefinition einen Kopierzuweisungsoperator nicht explizit deklariert, wird einer implizit deklariert. Der implizit deklarierte Kopierzuweisungsoperator für eine Klasse X hat die Form
X& X::operator=(const X&)
, wenn jede direkte Basisklasse B von X einen Kopierzuweisungsoperator hat, dessen Parameter vom Typ const B & amp; ist, const volatile B & amp; oder B, und für alle nichtstatischen Datenelemente von X, die von einem Klassentyp M (oder einem Array davon) sind, hat jeder derartige Klassentyp einen Kopierzuweisungsoperator, dessen Parameter vom Typ const M & amp; ist, const volatile M & amp; oder M.
Otherwise, the implicitly declared copy assignment operator will have the form X& X::operator=(X&)
...Ein Kopierzuweisungsoperator für die Klasse X ist trivial, wenn er implizit deklariert wird und wenn Klasse X keine virtuellen Funktionen (10.3) und keine virtuellen Basisklassen (10.1) hat und jede direkte Basisklasse von X ein Trivial hat Kopierzuweisungsoperator, und für alle nichtstatischen Datenelemente von X, die vom Klassentyp (oder Array davon) sind, hat jeder solche Klassentyp einen trivialen Kopierzuweisungsoperator ; Andernfalls ist der Kopierzuweisungsoperator nicht-trivial.
Ich bin mir nicht sicher, welcher Compiler korrekt ist, weil ich nicht weiß, ob ein konstantes Element einen trivialen Kopierzuweisungsoperator hat.
Bearbeiten: Die Kompilierungsbefehle sind:
%Vor% Bearbeiten2:
Um zu zeigen, dass sich g ++ nicht darüber beschwert, dass A :: b const
ist, aber A keinen Konstruktor hat, habe ich auch dieses Programm ausprobiert:
Dies kompiliert ohne Fehler sowohl in g ++ als auch in clang ++:
%Vor%Wie Sie richtig bemerkt haben, ist der Kopierzuweisungsoperator implizit deklariert und trivial. Dasselbe gilt für den Standardkonstruktor, der ebenfalls trivial und implizit deklariert ist.
Beachten Sie jedoch, dass diese beiden Member-Funktionen nicht implizit definiert sind - das passiert nur, wenn sie verwendet werden, [class.ctor] / 7:
Ein implizit deklarierter Standardkonstruktor für eine Klasse ist implizit definiert , wenn es zum Erstellen eines Objekts seines Klassentyps (1.8) verwendet wird.
.. was hier eindeutig nicht der Fall ist.
Das ist der Hauptunterschied und der Grund, warum das Zitat von @ dasblinkenlight in dieser Hinsicht irrelevant ist: Der Standardkonstruktor ist niemals definiert, daher gilt der Absatz über fehlende mem-initializer-id s nicht.
Wie sind const
Mitglieder und der Zuweisungsoperator verbunden? Hier:
Ein implizit deklarierter Kopierzuweisungsoperator ist implizit definiert , wenn einem Objekt seines Klassentyps ein Wert seines Klassentyps oder ein Wert eines von seinem Klassentyp abgeleiteten Klassentyps zugewiesen wird . Ein Programm ist schlecht gebildet, wenn die Klasse eine Kopierzuweisung hat Operator ist implizit definiert hat:
- ein nicht statisches Datenelement von
const
type oder [..]
Somit wäre das Programm fehlerhaft, wenn der Kopierzuweisungsoperator verwendet würde. Aber es ist nicht. Alle speziellen Memberfunktionen sind ausschließlich deklariert, und alle Einschränkungen für const
-ness von nicht statischen Datenmembern gelten nur für implizit definierte spezielle Memberfunktionen.
Als Beispiel nehmen Sie
%Vor% Welche Kompilierung unter GCC . Auch Ihr Programm sollte wohlgeformt sein, da alle Anforderungen an die Trivialität spezieller Mitgliederfunktionen von Gewerkschaftsmitgliedern von A
erfüllt werden.
Tags und Links const c++ language-lawyer c++03