Multimethoden in C++



  • Hallo Forum,
    ich habe mich mal daran versucht Multimethoden in C++ zu simulieren. Hier ist mein bisheriger Fortschritt mit Kommentaren im Quellcode.

    template < typename TReturnType, typename TType > // momentan nur ein Parameter für die Multimethode
    class Dispatch
    {
    public:
    	template < typename TFunction >
    	void setDispatch(TFunction&& fn) noexcept // definiert die Funktion für dieses Dispatch
    	{
    		dispatch_ = fn;
    	}
    
    	decltype(auto) dispatch()
    	{
    		if (dispatch_ != nullptr)
    		{
    			return std::forward<std::function<TReturnType(TType)>>(dispatch_); // gibt eine rValue-Referenz der Funktion zurück
    		} 
    		throw std::exception(""); // ruft std::terminate in operator() von class MultipleDispatch auf, wenn Funktion nicht definiert ist!
    	}
    private:
    	std::function<TReturnType(TType)> dispatch_; // Funktionwrapper, der auf nullptr zeigt, solange er nicht explizit einem Ziel zugewiesen wird
    };
    
    template < typename TReturnType, typename... TTypes > // Die eigentliche "Multimethode" in Form eines Funktors
    class MultipleDispatch
    {
    public:
    	template < typename TType, typename TFunction >
    	void setDispatch(TFunction&& fn) noexcept
    	{
    		std::get<Dispatch<TReturnType, TType>>(dispatchTable_).setDispatch(std::forward<TFunction>(fn));
    	}
    
    	template < typename TType >
    	TReturnType operator()(TType value) noexcept // überladener () Operator, um der Syntax eines Funktionsaufrufes zu ähneln ( Funktor )
    	{
    		return std::get<Dispatch<TReturnType, TType>>(dispatchTable_).dispatch()(value);
    	}
    
    private:
    	std::tuple<Dispatch<TReturnType, TTypes>...> dispatchTable_; // ein TUple das alle Variationen des Funktors enthält
    };
    
    // Beispiel zur Anwendung
    
    template < typename... TTypes >
    class Base
    {
    public:
    	virtual ~Base() {}
    public:
    	MultipleDispatch<void, TTypes...> foo; // Instanz des Funktors mit den gewünschten Typen
    };
    
    class Derived
    	: public Base<int, float>
    {
    public:
    	Derived()
    	{
    		// Hier werden die einzelnen Variation der Funktion definiert, je nach Typ des Templateparameters
    		foo.setDispatch<int>([this](int x) { std::cout << x << "\n"; }); // über this-Capture kann die Lambdafunktion auf die Member von Derived zugreifen !
    		foo.setDispatch<float>([this](float x) { std::cout << x * 2 << "\n"; });
    	}
    };
    
    int main()
    {
    	Base<int, float>* b = new Derived();
    	Derived d;
    
    	b->foo(5); // 5
    	b->foo(5.f); // 10
    	d.foo(10); // 10 
    	d.foo(10.f); // 20
    	/*d.foo(10.5);*/ // Compiletime error
    
    	delete b;
    
    	std::getchar();
    
    	return 0;
    }
    

    Wie findet ihr den Ansatz ? Mein nächstes Ziel ist es, Funktionen mit mehreren Parametern zu ermöglichen.



  • Irgendwie seh ich grad nicht, warum das jetzt Multimethoden sein sollten...



  • hm kanns sein, dass ich den falschen Begriff für mein Problem gegoogelt hab ? 😃 🤡


Anmelden zum Antworten