C++ Inheriting Constructors - G++ vs Clang++

  • Ersteller Ersteller VikingGe
  • Erstellt am Erstellt am
V

VikingGe

Gast
Guten Morgen,

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:
So aus dem Bauch raus würde ich sagen, dass das ein Bug im gcc ist. VS2015 compiliert deinen Code anstandslos und ich wüsste auch keinen Grund, warum das nicht funktionieren sollte. Wie genau compilierst du das Programm denn? Hast du mal versucht
Code:
Element _e = { 5 };
durch
Code:
Element _e{ 5 };
zu ersetzen?

Ansonsten würde ich die Frage mal bei Stackoverflow stellen. Da gibts wesentlich mehr c++ Experten.
 
Clang verhaelt sich an den Standard. GCC und Microsoft haben ihre eigenen Workarounds. Ich habe mal auch irgendwo gelesen, das Boost seine eigene Library hacken musste damit die mit GCC und MS compiler kompilieren. Funktioniert mit Clang uebrigens nativ!
 
Meh, sowas in der Richtung habe ich mir schon gedacht. Danke für die Antworten.
Bis vor gar nicht allzu langer Zeit war es eigentlich eher clang, der noch etwas special care brauchte, heute ist es umgekehrt...

Wie genau compilierst du das Programm denn?
Hatte ich ja geschrieben, g++ -std=c++11 oder c++14. Und

Code:
Element _e{ 5 };
ändert an dem Problem auch nichts.
 
Zurück
Oben