Rückgabewert überladen



  • Da wir gerade bei impliziter Konvertierung / unerwartetem Aufruf sind:
    Ich hatte mal das Problem, dass ich mir eine Vektorklasse<T> geschrieben habe, die einen Konstruktor mit Argument size_t size = 0 hatte. Dazu habe ich zwei (globale) Operatoren definiert, einmal operator+(myvector<T>, myvector<T>) und einmal operator+(myvector<T>, T). (Das ist jetzt leicht vereinfacht, sollte aber nichts ausmachen). Nun habe ich eine Memberfunktion im Vektor, die den Typ T zurückgibt. Bei folgendem Code:

    wxString tmp;
    wxString tmp2 = tmp + "Hello World!";
    

    gab mir der GCC einen Fehler aus: Error: Function returning an array (in meiner Funktion, die den Typ T zurückgibt), ausgelöst vom Operator +. Lösung: Entweder meinen eigenen operator+() in AddVectors() umbenennen oder statt der rohen Zeichenkette wxString("Hello World!") zu schreiben.
    Kann sich das jemand erklären?



  • wxSkip schrieb:

    Kann sich das jemand erklären?

    Ins blaue rein geraten: dein Ctor war nicht explicit.



  • Shade Of Mine schrieb:

    wxSkip schrieb:

    Kann sich das jemand erklären?

    Ins blaue rein geraten: dein Ctor war nicht explicit.

    Nein, war er nicht. Aber wie willst du ein Array mit int-Konstruktor aus char* oder wxString erstellen?



  • @wxSkip:
    GCC hat Versucht den operator+(myvector<T>, T) mit T = char[13] zu instanzieren.
    Dazu musste er wiederum myvector<T> mit T = char[13] instanzieren.
    Wenn dann in operator+(myvector<T>, T) eine Funktion von myvector<T> verwendet wurde (direkt oder indirekt), die T als Returnwert hat, dann führt das zu dem Versuch ein Array zurückzugeben.

    Bin mir jetzt nicht 100% sicher, aber ich denke der Compiler muss zumindest mal myvector<char[13]> instanzieren, zumindest die Konstruktoren. myvector<char[13]> könnte ja einen Konvertierungs-Ctor haben, der mit wxString funktioniert. operator+(myvector<char[13]>, char[13]) wäre dann ein möglicher Kandidat für die Overload-Resolution. Und um herauszubekommen ob es wirklich so ist, muss GCC myvector<char[13]> eben erstmal instanzieren.

    Ob dabei der operator+(myvector<T>, T) mit T = char[13] noch instanziert werden muss, wenn nach dem Instanzieren von myvector<char[13]> bereits feststeht dass es keine implizite Konvertierung gibt, weiss ich nicht. Ob ein Fehler ala "Function returning an array" unter SFINAE fällt oder nicht, weiss ich auch nicht. Die SFINAE Regeln hab' ich nie so ganz behirnt - also was zu einem Übersetzungsfehler führt, und was nur nach SFINAE die Funktion aus dem Candidate-Set ausschliesst.

    EDIT: ich glaube mich vage zu erinnern, dass im Standard steht, dass sämtliche eventuell in Frage kommenden Template-Funktionen erstmal instanziert werden müssen. Angenommen ich irre mich diesbezüglich nicht, bleibt immer noch die Frage was mit SFINAE ist.



  • @hustbaer: Mir ist bloß schleierhaft, wieso er meint, er könne einen wxString in einen myvector<T> konvertieren. Schließlich gibt es bloß den Konstruktor myvector::myvector(size_t i = 0).
    Es müsste ja wxString zu myvector<const char[]> konvertiert werden und dass der Compiler das zweite Argument matcht und dann gleich alle Template-Funktionen des ersten Arguments instantiiert, glaube ich nicht.



  • Warum nicht boost::any und boost::any_cast benutzen?



  • EDIT: Hier stand Müll.



  • wxSkip schrieb:

    @hustbaer: Mir ist bloß schleierhaft, wieso er meint, er könne einen wxString in einen myvector<T> konvertieren. Schließlich gibt es bloß den Konstruktor myvector::myvector(size_t i = 0).

    Da myvector<T> ein Template ist, könnte erstmal grundsätzlich eine Konvertierung möglich sein.
    Könnte ja eine Spezialisierung myvector<char[13]> geben, oder myvector<char[N]> oder was auch immer. Und so eine Spezialisierung könnte einen ctor(wxString cosnt&) haben.

    Und um herauszufinden welche Konstruktoren die Template-Klasse myvector<char[13]> hat, muss der Compiler myvector<char[13]> instanzieren. Dabei werden natürlich nicht alle Memberfunktionen von myvector<char[13]> instanziert.

    Das Instanzieren von myvector<char[13]> ist auch nicht das Problem, sondern das Instanzieren des operator + Templates.

    Der Compiler muss nämlich auch alle eventuell in Frage kommenden operator + Templates instanzieren, damit er sein Overload-Set bilden kann, damit er mit dem fertigen Overload-Set dann die Overload-Resolution starten kann. Um rauszubekommen ob er einen "besten" Kandidaten findet, mehrere gleich gute, oder gar keine.

    Vermutlich ergibt sich das Problem dadurch, dass der operator+(myvector<T>, T) irgendwo eine (Member)funktion von myvector<T> verwendet, die T als Returntyp hat. Hab ich eigentlich schon geschrieben. Und da operator+(myvector<T>, T) mit T = char[13] instanziert wird, knallt es an der Stelle.

    Und, jetzt fällt es mir wieder ein: SFINAE "erlaubt" diesen Fehler nicht, da er sich (vermutlich) im Funktionsrumpf befindet, und nicht schon im "Prototyp" zuschlägt. (Zumindest ist das das Verhalten das ich öfters beobachtet habe, wie gesagt: SFINAE ist für mich ganz dunkle Magie, muss ich mich erst noch weiter damit befassen um das halbwegs gut zu überglicken)



  • @FrEEzE2046:
    deswegen 🙂

    ccquestions schrieb:

    hustbaer schrieb:

    Ähnliche Funktionalität gibt es übrigens bereits fertig in der Boost, nennt sich boost::any .

    Ich habe mich bis jetzt bezüglich der boost Bibliothek und sogar der standard Bibliothek etwas zurückgehalten, da ich mich, auch wenn das alles verlockend klingt, noch selbst persönlich mit den Basics an der Quelle rumschlagen will, um so mein Verständnis zu verbessern. Gleich selbst aufwändigere Template Containerklassen etc zu schreiben hat mir persönlich jetzt trotz einiger immer wieder mal auftretender Probleme schon viel gebracht. Schreibe gerade zum ersten Mal an einem Programm, das den Namen auch wirklich langsam verdient hat... ( 10'000+ Zeilen ).



  • hustbaer schrieb:

    Vermutlich ergibt sich das Problem dadurch, dass der operator+(myvector<T>, T) irgendwo eine (Member)funktion von myvector<T> verwendet, die T als Returntyp hat. Hab ich eigentlich schon geschrieben. Und da operator+(myvector<T>, T) mit T = char[13] instanziert wird, knallt es an der Stelle.

    Nein, sieht nicht so aus. Ich frage mich aber sowieso, warum der Compiler dann nicht einfach erstmal nach der eventuellen Spezialisierung myvector<const char[13]> Ausschau halten kann, anstatt gleich die Funktionen zu spezialisieren. Hätte die Funktion gar kein zweites Argument mit dem Typ T, wäre er ja auch nicht auf die Idee gekommen, nach myvector<const char[13]> zu suchen.



  • hustbaer schrieb:

    @FrEEzE2046:
    deswegen 🙂

    Nun, boost::any kann man sich doch auch recht schnell selber schreiben 😉



  • Wäre b oost.variant da nicht besser geeignet?



  • wxSkip schrieb:

    Ich frage mich aber sowieso, warum der Compiler dann nicht einfach erstmal nach der eventuellen Spezialisierung myvector<const char[13]> Ausschau halten kann, anstatt gleich die Funktionen zu spezialisieren.

    Ich glaube mich zu erinnern, dass der Standard das vorschreibt. Müsste in der Sektion Overload-Resolution (Sektion 13 IIRC) zu finden sein.

    Hätte die Funktion gar kein zweites Argument mit dem Typ T, wäre er ja auch nicht auf die Idee gekommen, nach myvector<const char[13]> zu suchen.

    Äh. Huch? Hat sie aber. Verstehe jetzt nicht was du damit meinst. Lies im Standard nach, da stehen die genauen Regeln was das alles betrifft.



  • Na ja, gut. Ich belasse es jetzt mal bei einer Umbenennung in AddVectors().


Anmelden zum Antworten