Operator überladen: keine passende Funktion für Aufruf



  • Na ja, warum geht das dan bei konstanten Referenzen?
    Ich mein, der Speicher existiert ja nicht, aber lesen kann man die trotzdem?!
    Deswegen sagte ich das.

    Oh, mir fällt gerade was ein:
    Wenn ein temporäres Objekt an eine Funktion übergeben wird, existiert es ja noch.
    Aber warum gehen dann konstante Referenzen auf Objekte, die eigentlich verworfen werden (temporaries)?



  • der MSVC akzeptiert das komischerweise

    class A
      {
      int i;
    public:
      A () { i = 0; }
      A (A & a) { i = a. i; }
      A (int v) { i = v; }
      A f () { return A (0); }
      };
    
    int main ()
      {
      A a (1);
      A b = a. f ();
      return 0;
      }
    

    bei http://ideone.com kommt "error: no matching function for call to ‘A::A(A)’"

    ISO/IEC 14882:2011 sagt dazu:

    12.8 Copying and moving class objects
    2 A non-template constructor for class X is a copy constructor if its first
    parameter is of type X&, const X&, volatile X& or const volatile X&, and either
    there are no other parameters or else all other parameters have default arguments (8.3.6).



  • Ja existieren tun die noch. Es ist auch leicht falsch zu sagen, dass sie nicht mehr existieren und man deswegen nicht schreiben kann.

    Würde man schreiben können, würde es jedoch keinen Unterschied zwischen const und non-const geben, da das Objekt ja nach der Funktion eh wieder zerstört ist. Beispiel:

    class Foo
    {
    public:
    	Foo()
    	{
    		std::cout << "C-Tor" << std::endl;
    	}
    
    	~Foo()
    	{
    		std::cout << "D-Tor" << std::endl;
    	}
    };
    
    void bar(Foo const& f)
    {
    	std::cout << "Funktion" << std::endl;
    }
    
    int main()
    {
    	{
    		std::cout << "---------------" << std::endl;
    		bar(Foo());
    		std::cout << "---------------" << std::endl;
    	}
    
    	system("PAUSE"); // das system hier soll mal egal sein!!! 
                             // nur damit sich die konsole nicht sofort schliesst
    	return 0;
    }
    

    Und wie du hier an dem Beispiel siehst, sollte folgende Ausgabe kommen:

    ---------------
    C-Tor
    Funktion
    D-Tor
    ---------------
    Press any key to continue . . .
    

    Das schöne ist, in Zeile 15 kannst du das const entfernen und es läuft immer noch (getestet unter meinem Visual Studio 2012 -> MSVC 11.0.5xxx)

    Ich hab jetzt hier gerade weitergetestet:

    #include <iostream>
    #include <fstream>
    #include "BVH_Tree.h"
    
    class Foo
    {
    public:
    	Foo()
    		: x(0)
    	{
    		std::cout << "C-Tor " << x << std::endl;
    	}
    
    	~Foo()
    	{
    		std::cout << "D-Tor " << x << std::endl;
    	}
    
    	int x;
    };
    
    void bar(Foo & f)
    {
    	f.x = 5;
    	std::cout << "Funktion " << f.x << std::endl;
    }
    
    int main()
    {
    	{
    		std::cout << "---------------" << std::endl;
    		bar(Foo());
    		std::cout << "---------------" << std::endl;
    	}
    
    	system("PAUSE");
    	return 0x0;
    }
    

    Und das geht auch noch oO 😮
    Damit sind sowohl meine als auch Nathans Erklärungen von vorher falsch...

    Nachtrag:

    dd++ schrieb:

    ISO/IEC 14882:2011 sagt dazu:

    12.8 Copying and moving class objects
    2 A non-template constructor for class X is a copy constructor if its first
    parameter is of type X&, const X&, volatile X& or const volatile X&, and either
    there are no other parameters or else all other parameters have default arguments (8.3.6).

    D.h. ein Copy Constructor kann auch andere Parameter zusätzlich bekommen? (per default, damit ein parameterloser Aufruf möglich ist)



  • Nathan schrieb:

    Wenn ein temporäres Objekt an eine Funktion übergeben wird, existiert es ja noch.
    Aber warum gehen dann konstante Referenzen auf Objekte, die eigentlich verworfen werden (temporaries)?

    Aus praktischen Gründen.

    Eine non-const referenz auf ein temporäres Objekt ist immer fraglich: warum willst du ein temporäres Objekt ändern? Änderungen verfallen ja direkt wenn die Referenz out of scope geht.

    Wenn man an eine const referenz aber bindet, dann macht das aber oft sinn.

    Beispiel:

    void foo(std::string const& str) {}
    foo("hallo");
    

    hier erstelle ich ja ein temporäres string Objekt und binde es ann eine const referenz. Das macht Sinn und sollte erlaubt sein.

    PS:
    der VC++ ist hier fehlerhaft.
    Testet das ganze einfach auf ideone.
    -> http://ideone.com/6r2pCW



  • so 100%ig blicke ich im Moment noch nicht durch, aber andere Leute hatten das Problem auch schon

    http://stackoverflow.com/questions/6401818/non-const-copy-constructor-and-implicit-conversions-on-return-value



  • dd++ schrieb:

    so 100%ig blicke ich im Moment noch nicht durch, aber andere Leute hatten das Problem auch schon

    Was ist denn unklar?

    VC++ ist, wie so oft, nicht standardkonform. *schocker*



  • Nein!
    VS C++ ist nicht standardkonform?!
    ---
    Zum Thema: Wie genau sieht das eigentlich mit der internen Verwaltung von Referenzen aus, mit C++11 und Referenz auf Temporary?



  • VC++ hat eine Extension, die das binden von non-const LValue-Referenzen an RValues erlaubt. Es gibt auch keinen technischen Grund, der dagegen Spricht, aber aus semantischen Gruenden, wie bereits gesagt, geht das nur bei const-LValue-Referenzen.

    In C++11 hat man die RValue-Referenz eingefuehrt, mit denen das moeglich ist. Beispiel:

    struct Foo {};
    Foo&& foo = Foo{}; // ok
    foo.bar = 42; // ok
    

    Wird in erster Linie fuer Move-Semantiken und Perfect-Forwarding gebraucht.



  • Ich werd nie verstehen warum man ohne /Za kompiliert und dann jammert das der MSVC nicht standardkonform ist. oO



  • kleiner Troll schrieb:

    Ich werd nie verstehen warum man ohne /Za kompiliert und dann jammert das der MSVC nicht standardkonform ist. oO

    Weil man mit /Za nicht weit kommt 😉



  • windows header gehen halt nicht, aber die sind ja kaum überall eingebunden.


Anmelden zum Antworten