Mittels std::string zu Funktion gelangen



  • Na ja, ne Möglichkeit wäre sowas:

    #include <unordered_map>
    #include <iostream>
    #include <string>
    #include <stdexcept>
    
    class blubb
    {
      std::unordered_map<std::string, void (*) ()> functions_;
    
    public:
      template <typename R, typename... Args>
      R call(const std::string& name, Args... args)
      {
        auto found = functions_.find(name);
    
        if (found == functions_.end())
          throw std::runtime_error("blubb");
    
        return reinterpret_cast<R (*) (Args...)>(found->second)(args...);
      }
      template <typename F>
      void set(std::string name, F f)
      {
        functions_[std::move(name)] = reinterpret_cast<void (*) ()>(f);
      }
    };
    
    double add(double a, double b)
    {
      return a + b;
    }
    
    int main()
    {
      blubb b;
      b.set("add", add);
      std::cout << "5 + 3 = " << b.call<double>("add", 5.0, 3.0) << '\n';
    }
    

    Aber ehrlich gesagt.. super gefährlich und nicht gerade schön. Ich würde eher nach einer komplett anderen Lösung suchen, wenn unterschiedliche maps nicht in Frage kommen.



  • Danke schonmal für die Antworten.
    Doch doch, unterschiedliche Maps kommen in Betracht(werds vermutlich auch so machen), aber würde gerne wissen ob es da bessere/andere Standardlösungen gibt.



  • Hmmm, ärgerlich an der std::map variante ist(so wie ich das sehe), das man, auch wenn nur eine vorhanden ist, funktionen mit von anderen abweichender parameterzahl in eine extra std::map packen muss, da sie einen eigenen funktionenzeigertypen benötigen 😕



  • du könntest verschiedene structs als Parameter übergeben in denen dann die Parameter stecken

    greetz KN4CK3R



  • Namenloser324 schrieb:

    Heho, ich überlege mir gerade bzw. versuche herauszufinden, wie man es am besten löst eine Zuordnung und Aufrufung von std::string zu einer gewünschten Funktion zu erstellen.

    Wozu denn eigentlich?



  • krümelkacker schrieb:

    Namenloser324 schrieb:

    Heho, ich überlege mir gerade bzw. versuche herauszufinden, wie man es am besten löst eine Zuordnung und Aufrufung von std::string zu einer gewünschten Funktion zu erstellen.

    Wozu denn eigentlich?

    parser von arithmetischen ausdrücken bei denen auch noch einige funktionen aufrufbar sein sollen



  • Schreib deine Funktionen als T(vector<T>), wobei T der Werttyp ist.



  • struct value_type
    {
    	enum Enum
    	{
    		Integer,
    		Float,
    		Boolean,
    		Nil,
    	};
    };
    typedef value_type::Enum ValueType;
    
    typedef long long Integer;
    typedef double Float;
    typedef bool Boolean;
    
    struct Value
    {
    	ValueType type;
    	union
    	{
    		Integer i;
    		Float f;
    		Boolean b;
    	};
    
    	Value();
    	Value(Integer i);
    	Value(Float f);
    	Value(Boolean b);
    };
    
    Integer toInteger(const Value &value)
    {
    	switch (value.type)
    	{
    	case value_type::Integer: return value.i;
    	case value_type::Float: return static_cast<Integer>(value.f);
    	case value_type::Boolean: return value.b;
    	default: throw std::runtime_error("Not convertible to integer");
    	}
    }
    
    Float toFloat(const Value &value);
    
    typedef std::function<Value (const std::vector<Value> &)> Function;
    
    struct FunctionRegistry
    {
    	void add(std::string name, Function function);
    	Value call(const std::string &name, const std::vector<Value> &arguments) const;
    	//impl sollte klar sein
    
    private:
    
    	typedef std::map<std::string, Function> FunctionsByName;
    
    	FunctionsByName m_functionsByName;
    };
    
    static void expectArgumentCount(const std::vector<Value> &args, size_t count)
    {
    	if (args.size() != count)
    	{
    		throw std::runtime_error("Wrong argument count");
    	}
    }
    
    int main()
    {
    	FunctionRegistry reg;
    	reg.add("sin", [](const std::vector<Value> &args) -> Value
    	{
    		expectArgumentCount(args, 1);
    		return Value(
    			static_cast<Float>(std::sin(
    				toFloat(args[0]))));
    	});
    	cout << toFloat(reg.call("sin", std::vector<Value>(1, Value(123)))) << endl;
    }
    


  • Kellerautomat schrieb:

    Schreib deine Funktionen als T(vector<T>), wobei T der Werttyp ist.

    Gute Idee, der vector ist natürlich elegant.
    @TyRoXx
    wow, vielen dank, muss mir das erstmal ne weile anschauen bis ich da durchsteige 🙂 sehr cool!



  • Ne Frage zum Code von dir TyRoxx:

    was genau wird hier gemacht:

    reg.add("sin", [](const std::vector<Value> &args) -> Value
        {
            expectArgumentCount(args, 1);
            return Value(
                static_cast<Float>(std::sin(
                    toFloat(args[0]))));
        });
    

    ist da nicht aufruf der funktion mit definition verwechselt?!
    und wieso gibt es dort die geschweifte klammer? wird das array initialisiert?!



  • Das ist kein Array, das ist eine Lambadafunktion von C++11. Genaue Syntax am besten selber googeln.



  • Jonas OSDever schrieb:

    Das ist kein Array, das ist eine Lambadafunktion von C++11. Genaue Syntax am besten selber googeln.

    Ah, gut zu wissen, damit habe ich noch gar nicht gearbeitet, danke.


Anmelden zum Antworten