virtual template member function workaround gesucht



  • Wieso kannst du nicht einfach zusätzliche Container für deine ASkill und BSkill Objekte machen?



  • dot schrieb:

    Wieso kannst du nicht einfach zusätzliche Container für deine ASkill und BSkill Objekte machen?

    nurf schrieb:

    // 100 weitere, mehrere Veerbungsebenen
    

    Bisschen unschön.



  • @nurf: Warum genau musst du denn überhaupt rausfinden ob im Container ein ASkill drin ist?



  • dot schrieb:

    @nurf: Warum genau musst du denn überhaupt rausfinden ob im Container ein ASkill drin ist?

    Vermutlich will er ein Item o.ä. hinzufügen, falls der Spieler eine gewisse Fähigkeit besitzt.



  • Pi:

    error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
    

    Aber gut, dass du maulst 🙄



  • Michael E. schrieb:

    Pi:

    error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
    

    Aber gut, dass du maulst 🙄

    Da hier ein C++-Forum ist, darf er maulen 😉



  • C++Forum schrieb:

    Da hier ein C++-Forum ist, darf er maulen 😉

    Natürlich darf man sich über main ohne expliziten Rückgabewert beschweren. Das als "hässlichen MSVC-Schrott" abzutun, ist aber unüberlegter Unsinn, weil der VC das gar nicht schluckt.



  • Das bezog sich auch auf for_each du Pfeife. Lern Texte verstehen.



  • 314159265358979 schrieb:

    Das bezog sich auch auf for_each du Pfeife. Lern Texte verstehen.

    http://msdn.microsoft.com/en-us/library/c4x1w65f.aspx 😕



  • Geb ich gleich mal an dich weiter.



  • Mir ist schon klar was du gemeint hast.

    Aber bevor du dich hier so aufspielst, solltest du erstmal deine eigenen Texte fixen...



  • Vielleicht hast du auch einfach nur nicht verstanden.



  • Du meintest wohl dass MSVC noch nicht die neue range-based for Loop unterstützt!?
    Denn for_each ist Teil der Standardbibliothek und das unterstützt es natürlich...



  • Schritt 1: Code des TE nochmal ansehen.
    Schritt 2: Stichwort: Extension



  • Versuch mal folgendes, um der rtti Beine zu machen:

    inline unsigned int next_id()
    {
        static unsigned int current_id = 1;
    
        return current_id++;
    }
    template< class Type >
    class t_id
    {
        static const unsigned int value;
    };
    template< class Type >
    const unsigned int t_id< Type >::value = next_id();
    

    t_id< X >::value ist jetzt für jede Klasse einzigartig (Achtung: funktioniert vermutlich nicht, wenn dlls im Spiel sind).
    Jetzt kannst du noch die Suche von O( n ) auf O( 1 ) bringen:
    Statt linearer Suche verwendest du ein Hilfsarray. lookup_vector[ t_id< Type >::value ] soll die Anzahl der Objekte eines bestimmten Typs beinhalten. Dazu muss sich jedes Objekt in dem lookup_vector registrieren (inklusive aller base classes!), wenn es in den Container aufgenommen wird und abmelden, wenn es entfernt wird:

    template< class BaseType , class DerivedType >
    class derived_helper
      : public BaseType
    {
    public:
        static void add_indices( std::vector< unsigned int >& lookup_vector )
        {
            ++lookup_vector[ t_id< DerivedType >::value ];
            BaseType::add_indices( lookup_vector );
        }
        static void remove_indices( ... )
        {
             ...
        }
    };
    

    Wenn du davor hattest

    A;
    B : A;
    

    machst du jetzt halt

    A;
    B : derived_helper< A , B >
    

    Du musst also die alte codebase verändern, darum kommst du wohl nicht rum (sind aber minimale Änderungen, denke ich).
    Wenn du jetzt ein Objekt zu deinem Container hinzufügst, rufst du für den jeweiligen Type eben die add_indices funktion mit deinem std::vector< unsigned int > lookup_vector auf, wenn du eines entfernst die remove_indices funktion (Anm.: Falls du Objekte über einen base pointer übergibst muss die Funktion virtuell und nicht statisch sein).
    Deine has< T > funktion wird dann einfach ein

    template< class Type >
    bool has()
    {
        return lookup_vector[ t_id< Type >::value ] != 0;
    }
    

    Statt einem lookup_vector kann man denke ich auch eine andere Datenstruktur verwenden, beispielsweise ein set. Dadurch gewinnt man vielleicht etwas Speicher, verliert aber Zeit und hat wieder beim eine binary search drinnen, verliert also O( 1 ). Ist davon abhängig, wie viele verschiedene Typen tatsächlich im container gespeichert werden, was sinnvoller ist.



  • @dot: Der Code von nurf erinnert eher an etwas wie das:

    #define for_each(i, l) \
        for (__decltype((l).begin()) i=(l).begin(), i##_end=(l).end();
             i != i##_end; ++i)
    

    So nutzt nurf den Wurf:

    template <typename T> bool has()
      {
        for_each(skill, skills)
        {
           // hier liegt das Problem
           if (dynamic_cast<T*>(skill) != 0 )
           { return true; } // Guck mal da: returniert aus has()
        }
        return false;
      }
    


  • 314159265358979 schrieb:

    Schritt 1: Code des TE nochmal ansehen.
    Schritt 2: Stichwort: Extension

    MSVC hat keine for_each Extension, nur eine for each Extension. Das muss also irgendein Makro sein...



  • Abgesehen davon:

    main(...)
    

    Die "..." stören niemanden oder was? Vielleicht darüber nachgedacht, dass der TE nur Pseudocode gepostet hat, um zu veranschaulichen, worum es geht? Statt Hilfe kommt nur dummes Gelaber von language lawyern (naja, eigentlich nur einem) der keinem was bringt... wirklich unnötig.



  • Nur mal so ne Idee, ungetestet (weiss nichtmal ob es 1:1 so compiliert), aber müsste so oder so ähnlich hinhauen:

    class Container 
    { 
        std::vector<Skill*> skills; 
    
        typedef std::pair<intptr_t, intptr_t> SkillMapKey;
        typedef std::map<SkillMapKey, bool> SkillMap;  // evtl. hash_map verwenden wenns hier wirklich viele Einträge geben sollte
        SkillMap skillMap;
    
        SkillMapKey make_skill_map_key(Skill const* concreteSkill, type_info const& interfaceType)
        {
            return SkillMapKey(
                reinterpret_cast<intptr_t>(&typeid(*concreteSkill),
                reinterpret_cast<intptr_t>(&interfaceType));
        }
    
        template <typename T> bool has(Skill* concreteSkill)
        {
            SkillMapKey key = make_skill_map_key(concreteSkill, typeid(T));
    
            SkillMap::iterator it = skillMap.find(key);
            if (it != skillMap.end())
                return it->second;
            else
            {
                bool result = dynamic_cast<T*>(concreteSkill) != 0;
                skillMap[key] = result;
                return result;
            }
        }
    
        template <typename T> bool has() 
        { 
            for_each(skill, skills) 
            { 
                // hier jetzt hoffentlich schneller
                if (has<T>(skill)) 
                    return true;
            } 
    
            return false; 
        } 
    }
    

    Wenn der Inhalt des Containers recht statisch ist könnte man natürlich noch weiter optimieren, so dass die meisten Abfragen überhaupt keine Schleife mehr brauchen.

    ps: Falls "Skill" Objekte in DLLs/SOs implementiert sind, die dynamisch geladen oder und entladen werden könnte das Probleme machen. Davon abgesehen müsste es mMn. funktionieren.



  • GorbGorb schrieb:

    Statt Hilfe kommt nur dummes Gelaber von language lawyern (naja, eigentlich nur einem) der keinem was bringt... wirklich unnötig.

    Ja. Das Problem ist nur, dass man hier ohne genauere Information über die konkrete Anwendung keine hilfreiche Antwort geben kann. Denn eine gute Lösung für das Problem würde vermutlich eine grundlegende Änderung des Designs bedeuten. Und wie diese jetzt genau aussehen könnte kann man so allgemein nicht sagen...


Anmelden zum Antworten