Was ist der operator()()



  • Hallo an Alle!

    Kann man mir (so einfach wie möglich 🙂 ) erklären welcher Operator hier genau überschrieben wird und was ich damit dann tun kann ? Ich kapiere es nicht was das alles bedeuten soll. 😞
    https://en.cppreference.com/w/cpp/language/operators

    
    class MyClass
    {
    public:
        void operator()()     
        {
            for(int i = 0; i < 10000; i++)
                std::cout << i << std::endl;
        }
    };
    

    Grüße,



  • Guck mal hier:
    https://www.tutorialspoint.com/cplusplus/function_call_operator_overloading.htm

    Die Klasse hat nur einen "leeren" Konstruktor ohne Parameter.
    Aber der ()-Operator ist definiert mit drei Parametern. Dort wird das Objekt der Klasse erzeugt und dann per Direktzugriff auf die MemberVariablen initialisiert.

    Ich sehe es aber auch zum ersten Mal. Das war mir nicht bekannt, dass es sowas gibt und wozu man das braucht.



  • Das Teil nennt man nen Funktor, damit kannst du eine Instanz deiner Klasse wie eine Funktion aufrufen.



  • @It0101 sagte in Was ist der operator()():

    und wozu man das braucht.

    In pre-C++11 Zeiten waren das eine Möglichkeit für alles, wofür man heute Lambdas nimmt.
    Sowieso sind Lambdas ziemlich genau nur syntaktischer Zucker für functors.



  • @It0101 sagte in Was ist der operator()():

    wozu man das braucht

    Beispiel ist ein Distribution-Objekt aus random.

    std::uniform_int_distribution<int> dist(1, 100);
    // und dann:
    int randonNumber = dist(rng);
    

    Und dann hast du mit dist eben so ein Objekt, das du aufrufen kannst und das dann die Randomness aus einem rng in eine Verteilung umwandelt.

    Ein weiteres Beispiel ist std::less. Auch da hast du einen operator(), der gibt dann eben zurück, ob eine Zahl kleiner ist als die andere.



  • @Jockelx Manchmal möchte man aber einer nicht-trivialen Operationen einen sinnvollen Namen geben, oder sie wird an mehreren Stellen verwendet. Und da finde ich lambdas schon wieder weniger toll.



  • @HarteWare sagte in Was ist der operator()():

    @Jockelx Manchmal möchte man aber einer nicht-trivialen Operationen einen sinnvollen Namen geben, oder sie wird an mehreren Stellen verwendet. Und da finde ich lambdas schon wieder weniger toll.

    auto sinnvollerName = [](){…};
    


  • @Jockelx sagte in Was ist der operator()():

    @It0101 sagte in Was ist der operator()():

    und wozu man das braucht.

    In pre-C++11 Zeiten waren das eine Möglichkeit für alles, wofür man heute Lambdas nimmt.

    Nur als Ergänzung: es gibt auch heute noch Fälle wo man den () operator selbst implementiert weil Lambdas halt nicht immer passen.



  • @wob sagte in Was ist der operator()():

    Beispiel ist ein Distribution-Objekt aus random.

    std::uniform_int_distribution<int> dist(1, 100);
    // und dann:
    int randonNumber = dist(rng);
    

    Und dann hast du mit dist eben so ein Objekt, das du aufrufen kannst und das dann die Randomness aus einem rng in eine Verteilung umwandelt.

    Ein weiteres Beispiel ist std::less. Auch da hast du einen operator(), der gibt dann eben zurück, ob eine Zahl kleiner ist als die andere.

    Wobei man hier ja genau so gut eine benannte Funktion machen könnte. Man müsste sich bloss auf den Namen einigen (invoke?), und schwupps, könnte man wieder std::less und ähnliche "Funktoren" programmieren.

    Ich sehe folgende Gründe warum man trotzdem den operator () überladen können möchte:

    • Man schafft damit die Möglichkeit in Templates Funktionszeiger bzw. Funktionsreferenzen gleich zu behandeln wie Funktoren. Schreibt man ein Template das mit Funktoren "kann", kann es auch mit Funktionszeigern. Ohne operator() Overloading müsste man das Template ebenfalls für invoke-Style Funktoren schreiben, und dann mit einem Wrapper für Funktionszeiger arbeiten.
    • Es ist netter Syntactic Sugar für Objekte die quasi bloss eine einzige Funktion implementieren. Wobei ich der Meinung bin dass es z.T. overused wird. RNGs & Co. mit operator () finde ich persönlich z.B. komisch. In Templates sieht es aber IMO deutlich besser aus wenn da comp(x, y) steht statt comp.invoke(x, y).
    • Es gibt sowieso schon operator overloading, und dann spricht irgendwie nix dagegen auch () überladbar zu machen. (Im Gegensatz zu z.B. dem unären operator & aka. Adressoperator, dessen Überladung IMO grob das Principle of Least Astonishment verletzt -- und trotzdem ist auch der überladbar.)


  • @HarteWare
    @hustbaer sagte in Was ist der operator()():

    Nur als Ergänzung: es gibt auch heute noch Fälle wo man den () operator selbst implementiert weil Lambdas halt nicht immer passen.

    Ja, sehe ich nicht anders, hab das nur missverständlich geschrieben.



  • Hallo

    Ok da ich kein Wort verstanden habe 😒 . Frage ich mal anders.

    class MyClass
    {
    public:
        void operator()()     
        {
            for(int i = 0; i < 10000; i++)
                std::cout << i << std::endl;
        }
    };
    
    int main()
    {
        // ?????
        return 0;
    }
    

    Was schreibe ich bei "?????" hin damit die for Schleife durchlaufen wird ?

    @It0101 sagte in Was ist der operator()():

    Guck mal hier:
    https://www.tutorialspoint.com/cplusplus/function_call_operator_overloading.htm

    Die Klasse hat nur einen "leeren" Konstruktor ohne Parameter.
    Aber der ()-Operator ist definiert mit drei Parametern. Dort wird das Objekt der Klasse erzeugt und dann per Direktzugriff auf die MemberVariablen initialisiert.

    Ok das hilft mir noch am ehersten. Ab zu dem Beispiel

    class Distance {
       private:
          int feet;             // 0 to infinite
          int inches;           // 0 to 12
          
       public:
          // required constructors
          Distance() {
             feet = 0;
             inches = 0;
          }
          Distance(int f, int i) {
             feet = f;
             inches = i;
          }
          
          // overload function call
          /*Distance operator()(int a, int b, int c) {
             Distance D;
             
             // just put random calculation
             D.feet = a + c + 10;
             D.inches = b + c + 100 ;
             return D;
          }*/
    
          // ???
          Distance (int a, int b, int c) {
             Distance D;
             
             // just put random calculation
             D.feet = a + c + 10;
             D.inches = b + c + 100 ;
             return D;
          }
          
          // method to display distance
          void displayDistance() {
             cout << "F: " << feet << " I:" << inches << endl;
          }   
    };
    
    

    Und wo ist der Unterschied wenn ich Anstelle von "Distance operator()(int a, int b, int c)" Distance(int a, int b, int c) schreibe ?

    Grüße



  • Ich hab dir doch gesagt du erstellst ein Objekt deiner Klasse und rufst das Ding wie ne Funktion auf.



  • #include <iostream>
    
    class MyClass
    {
    public:
        void operator()()     
        {
            for(int i = 0; i < 10000; i++)
                std::cout << i << std::endl;
        }
    };
    
    int main()
    {
        MyClass m;
        m();
    }
    
    


  • @martin_zi sagte in Was ist der operator()():

    Und wo ist der Unterschied wenn ich Anstelle von "Distance operator()(int a, int b, int c)" Distance(int a, int b, int c) schreibe ?

    Grüße

    Nun mit dem ersten definierst Du den Funktionsoperator, mit dem zweiten einen Konstruktor..

    VG



  • Ahhhh ok ok danke jetzt it es klarer jetzt kann ich auch solche "Sachen" machen 🙂

    class MyClass
    {
    public:
    	int x =0;
    	MyClass()
    	{
    		std::cout<<"MyClass()"<<std::endl;
    	}
    	MyClass(int x)
    	{
    		this->x = x;
    		std::cout<<"MyClass(int x)"<<std::endl;
    	}
            void operator()()
            {
                    std::cout<<"operator()()"<<std::endl;
            }
    };
    
    int main()
    {
    	MyClass dThread1;
    	dThread1.x=5;
    	dThread1();
    
    	MyClass dThread2(2);
            dThread2();
    
    	MyClass(2)();
    
            return 0;
    }
    

Anmelden zum Antworten