Konstruktoraufruf in GCC funktioniert nicht
-
Doofer Titel aber mir fällt kein besserer ein.
Folgender Code kompiliert mit MSVC problemlos aber mit GCC nicht. Meiner Meinung nach ist der Code korrekt (ist ja auch trivial). Ich habe hier MS Visual Studio 2013 Express Edition und MinGW GCC 4.7.1, online auch getestet mit GCC 4.8.1.
Code:
struct Bar { }; template<typename T> class Foo { Foo(Foo& Rhs); Foo& operator= (Foo& Rhs); Foo(Foo const& Rhs); Foo& operator= (Foo const& Rhs); public: Foo(Bar const& Rhs) { } }; int main() { Foo<int> MyFoo = Bar(); }Meldung vom lokalen GCC:
main.cpp||In function 'int main()':| main.cpp|11|error: 'Foo<T>::Foo(const Foo<T>&) [with T = int; Foo<T> = Foo<int>]' is private| main.cpp|22|error: within this context|Meldung von Ideone's GCC:
prog.cpp: In function ‘int main()’: prog.cpp:11:2: error: ‘Foo<T>::Foo(const Foo<T>&) [with T = int]’ is private Foo(Foo const& Rhs); ^ prog.cpp:22:23: error: within this context Foo<int> MyFoo = Bar(); ^Wer hat recht? MSVC oder GCC?
-
Diese Art der Initialisierung erzeugt offiziell ein Bar, initialisiert damit ein temporäres Foo und initialisiert damit MyFoo über den Kopierkonstruktor. Der Umweg über den Kopierkonstruktor darf vom Compiler ausgelassen werden, aber der Kopierkonstruktor muss trotzdem vorhanden und zugänglich sein, als ob diese Optimierung nicht stattfinden würde.
(Irgendwo fehlt da noch was über Move-Konstruktoren, aber die gibts bei dir nicht und ich hab keine Lust nachzuschlagen. Ich nehme an, dass bei einem zulässigen move der Kopierkonstruktor nicht benötigt wird.)
-
Bashar schrieb:
(Irgendwo fehlt da noch was über Move-Konstruktoren, aber die gibts bei dir nicht und ich hab keine Lust nachzuschlagen. Ich nehme an, dass bei einem zulässigen move der Kopierkonstruktor nicht benötigt wird.)
Der zweite Schritt erfordert nur einen passenden Konstruktor. Copy-elision wird allerdings nur Copy- und Movekonstruktoren durchgeführt.
Das sind dann meist ungewöhnliche Konstrukte:
struct bar; struct foo { foo() {} foo(bar&&) {} }; struct bar : foo {}; struct foobar { operator bar() { return bar(); } }; foo x = foobar();
-
Bashar schrieb:
Diese Art der Initialisierung erzeugt offiziell ein Bar, initialisiert damit ein temporäres Foo und initialisiert damit MyFoo über den Kopierkonstruktor. Der Umweg über den Kopierkonstruktor darf vom Compiler ausgelassen werden, aber der Kopierkonstruktor muss trotzdem vorhanden und zugänglich sein, als ob diese Optimierung nicht stattfinden würde.
Das wusste ich nicht, ich dachte, die =-Schreibweise sei semantisch dasselbe für nicht-
explicitKonstruktoren.Edit: Problem hiermit gelöst, mit der Klammern-Schreibweise (resp. eben nicht Schreibweise sondern Version) funktioniert der Code wunderbar. Danke.