Default-Parameter "this"



  • Hallo zusammen,

    class Worker
    {
        public:
            template<typename T>
            void doSomething(T caller = this) // Fehler: 'this' may not be used in this context
            {
               std::cout << typeid(caller).name() << std::endl;
            }
    };
    
    class Foo
    {
        public:
            void run()
            {
                worker.doSomething(this);
            }
        private:
            Worker worker;
    };
    
    class Bar
    {
        public:
            void run()
            {
                worker.doSomething(this);
            }
        private:
            Worker worker;
    };
    
    int main(int argc, char *argv[])
    {
        Foo foo;
        Bar bar;
    
        foo.run(); // P3Foo
        bar.run(); // P3Bar
    
        return 0;
    }
    

    Ich möchte innerhalb der Funktion, die aufrufende Klasse kennen und hätte diesen Parameter gerne als Default-Parameter, so dass beim Aufruf "this" nicht explizit angegeben werden muss.

    Ich habe es so versucht, allerding ist "this" als Vorgabewert nicht möglich.

    Ist das überhaupt machbar?



  • Hallo,

    ich weiss es leider nicht, aber das Design finde ich überhaupt nicht gut.
    doSomething sollte frei oder member sein, aber nicht mal so mal so (bei dir technisch nicht frei aber semantisch).



  • Ist zwar nur ne Krücke, aber vllt hilfts:

    class Worker
    {
      ...
      template<typename T>
      void doSomething( T* Caller )
      {
         ...
      }
    
      void doSomething()
      {
         doSomething( this );
      }
    }
    

    Noch was zu Templates:
    T ist von sich aus kein Pointer-Typ, da musst du schon T* benutzen. Vllt klappt deshalb die Verwendung von this nicht?



  • Jockelx schrieb:

    Hallo,

    ich weiss es leider nicht, aber das Design finde ich überhaupt nicht gut.
    doSomething sollte frei oder member sein, aber nicht mal so mal so (bei dir technisch nicht frei aber semantisch).

    Tut mir leid, aber ich verstehe nicht was du mir sagen möchtest. Kannst du das bitte für eine Nicht-Profi erklären?

    frei = freie Funktion?
    member = Klassenfunktion?
    mal so mal so = ? (Es gibt die Funktion doch nur einmal und zwar als Klassenfunktion von Worker)



  • DocShoe schrieb:

    Ist zwar nur ne Krücke, aber vllt hilfts:

    class Worker
    {
      ...
      template<typename T>
      void doSomething( T* Caller )
      {
         ...
      }
    
      void doSomething()
      {
         doSomething( this );
      }
    }
    

    Noch was zu Templates:
    T ist von sich aus kein Pointer-Typ, da musst du schon T* benutzen. Vllt klappt deshalb die Verwendung von this nicht?

    Nö, die Krücke geht nicht, weil da ja this auf Worker zeigt.

    T* hatte ich auch schon mal probiert, dass hat auch nicht geklappt.

    Danke trotzdem.



  • temi schrieb:

    Jockelx schrieb:

    Hallo,

    ich weiss es leider nicht, aber das Design finde ich überhaupt nicht gut.
    doSomething sollte frei oder member sein, aber nicht mal so mal so (bei dir technisch nicht frei aber semantisch).

    Tut mir leid, aber ich verstehe nicht was du mir sagen möchtest. Kannst du das bitte für eine Nicht-Profi erklären?

    frei = freie Funktion?
    member = Klassenfunktion?

    Ja, das meinte ich.

    temi schrieb:

    mal so mal so = ? (Es gibt die Funktion doch nur einmal und zwar als Klassenfunktion von Worker)

    Ne Klassenfunktion ist ja deshalb ne Klassenfuntion, weil sie member der Klasse nutzt. Sonst kann sie ja besser frei sein.
    In deinem Fall nutzt sie aber nur member, wenn man doSomething() aufruft.
    Bei doSomething(bla) verhält sie sich wie eine freie Funktion.

    Deshalb würde ich ein konsistentes bla.doSomething() oder doSomething(bla) bevorzugen.



  • temi schrieb:

    ...
    Nö, die Krücke geht nicht, weil da ja this auf Worker zeigt.
    ...

    Genau das drückst du doch bei einer Member-Funktion aus. this bezieht sich immer auf die beinhaltende Klasse.
    Korrigier mich, wenn ich da was falsch verstehe:
    Was du möchtest, ist nicht this des Workers, sondern das this (that? :D) des Aufrufers? Dafür gib´s in C++ keine Sprachmittel, außer halt Parameter.



  • DocShoe schrieb:

    Was du möchtest, ist nicht this des Workers, sondern das this (that? :D) des Aufrufers? Dafür gib´s in C++ keine Sprachmittel, außer halt Parameter.

    Genau. In C# war das, soweit ich mich erinnern kann, möglich. Danke erst mal.



  • Aber warum soll dann der Parameter überhaupt einen Default-Wert bekommen?



  • Belli schrieb:

    Aber warum soll dann der Parameter überhaupt einen Default-Wert bekommen?

    // irgendwo in einer Klasse die worker verwendet
    worker.doSomething(); // this würde per default übergeben...
    

    Damit stillschweigend das aufrufende Objekt an Worker übergeben wird, sobald die Funktion aufgerufen wird und damit worker weiß, von wem er aufgerufen wurde.

    Der Haken an der Sache wäre allerdings, dass diese Info durch Angabe eines Parameters gefälscht werden könnte. Auch blöd. Mindestens genauso blöd wie eine Funktionsdoku in der steht: "An dieser Stelle immer 'this' verwenden!".



  • Warum muss der Worker das wissen?



  • temi schrieb:

    Damit stillschweigend das aufrufende Objekt an Worker übergeben wird

    Keine Ahnung, was Du meinst, aber Du rufst doch

    worker.doSomething(this);
    

    aus bar und aus foo auf, da ist nix stillschweigendes (ist auch nicht möglich).



  • Dieses Template ist halt eh sinnlos, wenn du this als Default-Parameter angibst. this ist immer das gleiche, ein Zeiger auf die jeweilige Instanz von Worker.

    Mach Überladungen.



  • Belli schrieb:

    temi schrieb:

    Damit stillschweigend das aufrufende Objekt an Worker übergeben wird

    Keine Ahnung, was Du meinst, aber Du rufst doch

    worker.doSomething(this);
    

    aus bar und aus foo auf, da ist nix stillschweigendes (ist auch nicht möglich).

    Ähm, ja. Da es offenbar nicht anders möglich ist, habe ich das so gemacht, wobei der Wunsch und die Frage lautete, ob (wie auch immer) "this" als Default-Parameter möglich ist, damit ich es eben nicht beim Aufruf angeben muss. Da es nicht geht (und weil die Idee noch ein paar Haken hat), hat sich das erledigt

    Gruß,
    temi



  • DocShoe schrieb:

    Warum muss der Worker das wissen?

    Das ist geheim 😉

    Nein, natürlich nicht. Worker soll abhängig vom aufrufenden Objekt die übergebenen Daten anders behandeln und dazu parametrierbar sein, z.B. (PSEUDOCODE!)

    FileWorker schreibt Daten in eine Datei.
    DbWorker schreibt Daten in eine Datenbank.

    FileWorker fw;
    fw.canHandle(Foo);
    fw.canHandle(Bar);
    
    DbWorker dw;
    dw.canHandle(Foo);
    
    CompositWorker worker; // verhält sich wie ein Worker
    worker.add(fw);
    worker.add(dw);
    
    Foo foo(worker);
    Bar bar(worker);
    
    foo.run(); // wird von Fileworker und von DbWorker behandelt
    bar.run(); // wird nur von DbWorker behandelt
    

    Das war die Grundidee.



  • Das klingt, als ob

    Foo foo(worker);
    Bar bar(dw);
    

    vernünftig wäre ...



  • Belli schrieb:

    Das klingt, als ob

    Foo foo(worker);
    Bar bar(dw);
    

    vernünftig wäre ...

    Nö.

    CompositWorker worker;
    worker.configFromFile("worker.config");
    ...
    

Log in to reply