override virtual function from variadic template inheritance



  • hallo in die runde,

    ich weiß nicht genau wie ich darauf kam, aber dieses gedankenspiel lässt mich gerade nicht mehr los: gegeben sei eine basisklasse, die T als template parameter hat und eine virtuelle funktion do_something die von T abhängig ist. eine andere klasse hat diese zur basis und zwar mittels template parameter pack expansion. wie bekomme ich es gebacken, T oder die do_something funktion "zu entpacken" damit es die virtuelle funktion überschreibt.

    es hat für mich keine praktische anwendung, sondern eher einen lerneffekt - gerade in bezug auf templates und variadic templates. da dieses konstrukt einfach zu erzeugen ist, dachte ich die lösung sollte genauso einfach sein, bis ich es probiert habe 😆 übersehe ich etwas? vielleicht über umwege wie helferklassen/-funktionen? oder ist es überhaupt nicht möglich?

    template <typename T> struct base_class
    {
        virtual void do_something (const T& param) = 0;
    };
    
    template <typename ...T> struct derived_class : public base_class <T>...
    {
        void do_something (const T&... param) override {}                    // tut natürlich nicht was ich gern hätte
        template <typename U> void do_something (const U& param) override {} // auch eine nullnummer
        void do_something (const T&... param)... override {}                 // so in der art wäre es "gemeint"
        void do_something (const T& param) override {}                       // funktioniert wenn es nur 1 T gibt
    };
    


  • Das ist so direkt unmöglich.

    Das ist das nächstbeste was mir eingefallen ist und nach kurzem überlegen konnte ich das virtual streichen, weil eh sinnlos.
    Außerdem brauch ich die Hilfsfunktion (member or non-member) um die Funktionen überhaupt aufzurufen.
    Sonst wird es heißen main.cpp|error: request for member 'do_something' is ambiguous in multiple inheritance lattice

    template <typename T>
    struct base_class
    {
        std::function <void(T const&)> fn_;
    
        explicit base_class(std::function <void(T const&)> fn)
            : fn_{std::move(fn)}
        {
        }
    
        void do_something(const T& p)
        {
            fn_(p);
        };
    };
    
    template <typename ...T>
    struct derived_class : base_class <T>...
    {
        explicit derived_class(std::function <void(T const&)>... fns)
            : base_class <T>
            (
                std::move(fns)
            )...
        {
        }
    
        template <typename U>
        void do_in_derived(U const& p)
        {
            static_cast <base_class <U>&>(*this).do_something(p);
        }
    };
    
    template <typename T, typename U>
    void call_unambiguous(U& u, T const& p)
    {
        static_cast <base_class <T>&>(u).do_something(p);
    }
    
    struct Bla{};
    
    int main()
    {
        derived_class <int, Bla> dc {
            [](auto const&){std::cout << "a";},
            [](auto const&){std::cout << "b";}
        };
    
        dc.do_in_derived(2);
        dc.do_in_derived(Bla{});
        //call_unambiguous(dc, 2);
        //call_unambiguous(dc, Bla{});
    }
    

    EDIT: Helfer muss nicht non-member sein.


Anmelden zum Antworten