Definieren von std::map<std::string,std::function<MYTYPE>> will nicht



  • Hi,

    da switch ja leider keine std::strings unterstützt und ich eine Lösung dafür via Funktionspointer gesehen hatte wollte ich diese Implementieren, daher versuche ich folgende map zu initialisieren:

    typedef std::unordered_map<std::string, std::function<constptr<Component>(FactoryWorker*,const AttributeList& attributes)>> ComponentHashTable
    

    das mache ich so:

    void FactoryWorker::setupHashTable()
    {
        m_componenthashtable["movement"]  = &FactoryWorker::buildMoveComponent;
        m_componenthashtable["health"]    = &FactoryWorker::buildHealthComponent;
        m_componenthashtable["collision"] = &FactoryWorker::buildCollisionComponent;
        m_componenthashtable["attack"]    = &FactoryWorker::buildAttackComponent;
        m_componenthashtable{"select"]    = &FactoryWorker::buildSelectComponent;
        m_componenthashtable["ai"]        = &FactoryWorker::buildAiComponent;
    }
    

    Irgendwas scheint da prinzipiell nicht zu gehen, ich erhalte nämlich folgende sinnfreie Fehlermeldung (bezieht sich auf Zeilen in setupHashTable():

    ||=== Build: Debug in ComponentBasedDesign (compiler: GNU GCC Compiler) ===|
    In member function 'void FactoryWorker::setupHashTable()':|
    error: expected ';' before '{' token|
    warning: statement has no effect [-Wunused-value]|
    error: expected '}' at end of input|
    ||=== Build failed: 2 error(s), 1 warning(s) (0 minute(s), 3 second(s)) ===|

    Z.B. bezieht sich der "statement has no effect" Fehler auf die schließende geschweifte Klammer der gesamten Funktion.

    Klassendefinition sieht so aus:

    class FactoryWorker
    {
    private:
        typedef std::vector<std::pair<std::string,std::string>> AttributeList;
        typedef std::unordered_map<std::string, std::function<constptr<Component>(FactoryWorker*,const AttributeList& attributes)>> ComponentHashTable;
    
        void setupHashTable();
        ComponentHashTable m_componenthashtable;
    
        constptr<Component> buildAttackComponent(const AttributeList& attributes);
        constptr<Component> buildCollisionComponent(const AttributeList& attributes);
        constptr<Component> buildHealthComponent(const AttributeList& attributes);
        constptr<Component> buildMoveComponent(const AttributeList& attributes);
        constptr<Component> buildSelectComponent(const AttributeList& attributes);
        constptr<Component> buildAiComponent(const AttributeList& attributes);
    
    public:
        explicit FactoryWorker()
        { setupHashTable(); }
    
        constptr<Component> buildComponent(const std::string& name, const AttributeList& attributes);
    
    };
    

    Wie macht man das richtig? Lambdas? Hatte ich auch schon versucht, aber war scheinbar auch falsch.

    Könnte vielleicht jemand eine korrekte Formulierung eines std::function Objekts für meinen Fall raushauen? Wäre super!



  • Oh mein Gott, lol.

    Wenn man ganz genau hinschaut hatte sich statt eine eckigen eine geschweifte Klammer eingeschlichen...

    m_componenthashtable{"select"]
    ...

    Hat sich damit geklärt.
    Falls das mal jemand finden sollte, es ging so:

    m_componenthashtable["select"]    = [this](const AttributeList& attributes) -> constptr<Component> { return buildSelectComponent(attributes); };
    

    Sieht schlecht aus und ist auch schlecht, muss mir was besseres überlegen.



  • So ein Schwachsinn, in C++ mit Funktionspointern zu arbeiten.
    Hast du schon mal was von Vererbung gehört?



  • Namenloser324 schrieb:

    da switch ja leider keine std::strings unterstützt und ich eine Lösung dafür via Funktionspointer gesehen hatte wollte ich diese Implementieren, daher versuche ich folgende map zu initialisieren:

    Benutz Typedefs, das ist sonst grauenhaft zu lesen.

    Du musst die Memberfunktionszeiger an ein this-Objekt binden, z.B. mit std::bind() . Woher soll std::function sonst wissen, auf welchem Objekt du die Memberfunktion aufrufst?

    Wutz schrieb:

    So ein Schwachsinn, in C++ mit Funktionspointern zu arbeiten.
    Hast du schon mal was von Vererbung gehört?

    So ein Schwachsinn, für einzelne Funktionen Vererbung zu nutzen. Hast du schon mal was von Funktionsobjekten gehört?

    std::function ist oft besser als Vererbung mit einer einzigen virtuellen Funktion. Du sparst dir erstens den ganzen Boilerplate-Code für die Klassenhierarchie, zweitens musst du dich nicht um dynamische Speicherverwaltung kümmern, sondern hast Funktionsobjekte mit Wertsemantik.

    Sogar Java hat mittlerweile eingesehen, dass kürzerer Code teilweise doch besser ist und Lambda-Ausdrücke eingebaut.



  • Nexus schrieb:

    Namenloser324 schrieb:

    da switch ja leider keine std::strings unterstützt und ich eine Lösung dafür via Funktionspointer gesehen hatte wollte ich diese Implementieren, daher versuche ich folgende map zu initialisieren:

    Benutz Typedefs, das ist sonst grauenhaft zu lesen.

    Du musst die Memberfunktionszeiger an ein this-Objekt binden, z.B. mit std::bind() . Woher soll std::function sonst wissen, auf welchem Objekt du die Memberfunktion aufrufst?

    Ja, das hatte ich auch schon gelesen und implementiert, es war nur ebenso, dass an einer sehr unglücklichen Stelle schlicht ein Tippfehler vorlag der als solcher nicht vom Compiler angegeben wurde (war halt eine geschweifte Klammer die dann zu Folgefehlern geführt hatte)

    Zu den Typedefs:
    Benutz ich ja schon, warte für n paar Sachen noch auf eine schöne Namenseingebung^^

    Danke für deine Hilfe 🙂



  • Namenloser324 schrieb:

    Zu den Typedefs:
    Benutz ich ja schon, warte für n paar Sachen noch auf eine schöne Namenseingebung^^

    Ich würde mehr benutzen. Der Typ

    std::unordered_map<std::string, std::function<constptr<Component>(FactoryWorker*,const AttributeList& attributes)>>
    

    ist zu lang.


Log in to reply