V
VikingGe
Gast
Guten Morgen,
ich hätte da gerne mal ein Verständnisproblem, was den Standard angeht. Folgende Situation als Minimalbeispiel:
Also die wichtigsten Punkte:
- Base und Element haben keine Default-Constructor
- Derived initialisiert eine Instanz von Element
Das Problem: clang compiliert das ganze ohne zu meckern und tut das, was man intuitiv erwartet. g++ (Version 5.1) schmeißt aber einen Haufen Fehler:
Workaround Nummer 1: Man schreibt das, was using Base::Base; eigentlich implizit machen soll, explizit hin, also
Workaround Nummer 2: Man gibt Element einen Default-Constructor, was allerdings a) keinen Sinn ergibt und b) auch nicht unbedingt möglich ist. Aber mal als Test:
Interessant an dieser Stelle: Die Ausgabe sowohl von der g++-Binary als auch von der clang++-Binary ist Element::Element(int), der Default-Constructor von Element wird also auch von g++ gar nicht benutzt.
Die Frage ist, wer hält sich da jetzt nicht an den Standard? Das clang-Verhalten ist ja eigentlich deutlich intuitiver, weil der geerbte Konstruktor eben nichts anderes machen soll als
- den Basisklassenkonstruktor aufzurufen und
- seine eigenen Member mit den angegebenen Standardwerten zu initialisieren.
ich hätte da gerne mal ein Verständnisproblem, was den Standard angeht. Folgende Situation als Minimalbeispiel:
Code:
class Element {
public:
Element(int) { }
};
class Base {
public:
Base(int) { }
};
class Derived : public Base {
public:
using Base::Base;
private:
Element _e = { 5 };
};
int main(int argc, char** argv) {
Derived d(5);
return 0;
}
Also die wichtigsten Punkte:
- Base und Element haben keine Default-Constructor
- Derived initialisiert eine Instanz von Element
Das Problem: clang compiliert das ganze ohne zu meckern und tut das, was man intuitiv erwartet. g++ (Version 5.1) schmeißt aber einen Haufen Fehler:
Code:
$ g++ -std=c++14 test.cpp
test.cpp: In Funktion »int main(int, char**)«:
test.cpp:19:14: Fehler: gelöschte Funktion »Derived::Derived(int)« wird verwendet
Derived d(5);
^
test.cpp:13:15: Anmerkung: »Derived::Derived(int)« wird implizit gelöscht, da die Standarddefinition ungültig wäre:
using Base::Base;
^
test.cpp:13:15: Fehler: keine passende Funktion für Aufruf von »Element::Element()«
test.cpp:3:3: Anmerkung: candidate: Element::Element(int)
Element(int) { }
^
test.cpp:3:3: Anmerkung: Kandidat erwartet 1 Argument, 0 angegeben
test.cpp:1:7: Anmerkung: candidate: constexpr Element::Element(const Element&)
class Element {
^
test.cpp:1:7: Anmerkung: Kandidat erwartet 1 Argument, 0 angegeben
test.cpp:1:7: Anmerkung: candidate: constexpr Element::Element(Element&&)
test.cpp:1:7: Anmerkung: Kandidat erwartet 1 Argument, 0 angegeben
Workaround Nummer 1: Man schreibt das, was using Base::Base; eigentlich implizit machen soll, explizit hin, also
Code:
class Derived : public Base {
public:
Derived(int a)
: Base(a) { }
[...]
Workaround Nummer 2: Man gibt Element einen Default-Constructor, was allerdings a) keinen Sinn ergibt und b) auch nicht unbedingt möglich ist. Aber mal als Test:
Code:
class Element {
public:
Element() { cout << "Element::Element()" << endl; }
Element(int) { cout << "Element::Element(int)" << endl; }
};
Interessant an dieser Stelle: Die Ausgabe sowohl von der g++-Binary als auch von der clang++-Binary ist Element::Element(int), der Default-Constructor von Element wird also auch von g++ gar nicht benutzt.
Die Frage ist, wer hält sich da jetzt nicht an den Standard? Das clang-Verhalten ist ja eigentlich deutlich intuitiver, weil der geerbte Konstruktor eben nichts anderes machen soll als
- den Basisklassenkonstruktor aufzurufen und
- seine eigenen Member mit den angegebenen Standardwerten zu initialisieren.
Zuletzt bearbeitet: