Funktion als Template-Argument



  • Ich möchte einer Klasse einen Funktor oder eine Funktion übergeben und diese dann von der Klasse aus ausführen.

    Folgender Code scheint zu funktionieren:

    #include <iostream>
    
    template <typename F>
    class Executor
    {
    public:
        typedef F functor_type;
    
        functor_type &f;
    
        void operator()()
        {
            f();
        }
    
        Executor(F& foo): f(foo) {}
    };
    
    class Functor
    {
    public:
        void operator()()
        {
            std::cout << "Functor is working" << std::endl;
        }
    };
    
    void function()
    {
        std::cout << "Function is working" << std::endl;
    }
    
    int main()
    {
        {
            Functor functor;
            Executor<Functor> exe(functor);
        }
        {
            Executor<decltype(function)> exe(function);
            exe();
        }
    
        return 0;
    }
    

    Was mir allerdings nicht gefällt, ist dass im Falle eines Funktors eine Referenz gespeichert wird. Ich befürchte, dass der Executor nur solange gültig ist, wie der im Konstruktor übergebene Funktor.

    Versuche ich die Referenz zu beseitigen zb mit

    functor_type f;
    

    erhalte ich

    field ‘Executor<void()>::f’ invalidly declared function type
    

    Kann mir jemand zeigen, wie man mein Problem elegant und sicher lösen kann?


  • Mod

    z.B. durch Indirektion

    template <typename F>
    class Executor
    {
    public:
        typedef F functor_type;
        using value_type = std::conditional_t<std::is_function_v<F>,F*,F>;
        value_type f;
    
        void operator()()
        {
            f();
        }
    
        Executor(value_type foo): f(foo) {}
    };
    


  • Ist nicht die üblichere Variante das an der Aufrufsstelle zu fixen?
    Also einfach

    Executor<decltype(function)*> exe(function);
    

    Funktionen kann man schliesslich sowieso nicht übergeben, maximal Referenzen auf Funktionen. Von daher macht es mMn. auch wenig Sinn das Template mit einem Funktionstyp zu instanzieren. Bzw. würde ich den zusätzlichen Aufwand im Executor Template nicht haben wollen, nur damit etwas was mMn. streng genommen sowieso falsch ist zu erlauben.


  • Mod

    camper schrieb:

    z.B. durch Indirektion

    template <typename F>
    class Executor
    {
    public:
        typedef F functor_type;
        using value_type = std::conditional_t<std::is_function_v<F>,F*,F>;
        value_type f;
     
        void operator()()
        {
            f();
        }
     
        Executor(value_type foo): f(foo) {}
    };
    

    Nennt sich auch std::decay


Anmelden zum Antworten