virtual template member function workaround gesucht



  • Danke schonmal für die vielen Anregungen.
    Das mit dem for_each hatte ich nur zur anschaulichen Vereinfachung eingebaut.

    Mir schwebt eigentlich eher sowas vor, wie jeder Klasse eine eindeutige ID/Enum zu geben. Dann könnte man sowas machen wie:

    template <typename T> bool has() const
    {
      return (T::ID == this->ID());
    }
    

    Mit dem Ziel die ID zur Compile-Zeit zu vergeben (notfalls muss man die Klassen-IDs in einem anderen Header pflegen, als Enum).

    Über die "letzte" Idee von hustbär hatte ich auch schon nachgedacht, das Problem von virtual templates durch eine weitere Indirektion zu lösen.

    Wenn der Lookup der typeid schneller ist als dynamic_cast, kann man für eine reine has-Prüfung auch auf die typeid umsteigen.



  • Erklär uns doch mal, um was für eine konkrete Problemstellung es da eigentlich geht...



  • //TypeID.hpp
    extern int t_id_counter;
    
    template<typename T> int GetTypeID()
    {
        static int i = -1;
        if(i == -1) i = t_id_counter++;
        return i;
    }
    
    //TypeID.cpp
    #include "TypeID.hpp"
    int t_id_counter = 0;
    

    EDIT: Ist zwar nicht Compile-Zeit, dafür aber der Runtime-Aufwand zu vernachlässigen. Eine Compilezeit-ID wird wohl nur mit irgendwelchem typeid()-Kram (und damit nicht standardkonform) generierbar sein (vielleicht erst mit C++11), aber dann auch nur, wenn man aus typeid(T).name() eine eindeutige ID generiert, die demzufolge länger als int wäre...

    Und was spricht gegen einen Referenzzähler?



  • nurf schrieb:

    Mir schwebt eigentlich eher sowas vor, wie jeder Klasse eine eindeutige ID/Enum zu geben. Dann könnte man sowas machen wie:

    template <typename T> bool has() const
    {
      return (T::ID == this->ID());
    }
    

    dynamic_cast tut aber mehr, als nur eine id vergleichen. Folgendes Szenario:

    A
    B : A
    C : B
    
    container.add( C() );
    container.has< B >();
    

    Wird mit dieser Methode false ergeben. Was du tun könntest, ist ein bitset zu verwenden, in das sich jede base class an der Stelle Base::ID einträgt. Dazu müsstest du aber wieder die alten header files verändern oder jede Vererbungsbeziehnung manuell irgendwie neu bekannt machen (um diesen Schritt kommst du aber nicht rum, wenn du rtti komplett ersetzen willst, du musst über die Vererbungsbeziehnungen irgendwie Bescheid wissen).



  • GorbGorb schrieb:

    Wird mit dieser Methode false ergeben. Was du tun könntest, ist ein bitset zu verwenden,

    Oder noch einfacher:
    Statt getID() eine Funktion hasID() verwenden die an den parent weiter reicht wenn false rauskommt 😉

    Aber wir brauchen eine genaue definition der Anforderung um eine gute Antwort geben zu koennen.



  • Shade Of Mine schrieb:

    Aber wir brauchen eine genaue definition der Anforderung um eine gute Antwort geben zu koennen.

    Prinzipiell stehen die Anforderungen im ersten Post.
    Das Kind ist in den Brunnen gefallen, weil das ganze Design und nun außerdem die Performance schlecht ist. Profiling-Analyse sagt dynamic_cast zieht zu viel CPU-Last.
    Wie erwähnt geht um viele Klassen, die in 2. oder 3. Stufe von der Basis-Klasse abgeleitet sind.
    **Ziel:**Performance verbessen, bspw. den dynamic_cast irgendwie obsolete machen. Weitere Ziele wären: möglichst viel zur Compile-Zeit (boost::is_same<A,B>) oder möglichst anfängersicher.
    Eine realistische absolut häßliche Möglichkeit wäre es auch alle Class-Test-Routinen in die Basis-Klasse zu verlagern und dann bei Bedarf zu überschreiben.

    class BaseSkill 
    {
      virtual bool hasASkill() { return false; }
      virtual bool hasBSkill() { return false; }
    }
    class ASkill : public BaseSkill
    {
      virtual bool hasASkill() { return true; }
    }
    

    Ob nun templatisiert oder nicht spielt für den eigentlichen C++-Business-Code keine direkte Rolle, ob nun

    if(unit->has<ASkill>()) ...
    if(unit->hasASkill()) ...
    

    Deswegen bin ich für gute Ideen weitestgehend offen.



  • wxSkip schrieb:

    Und was spricht gegen einen Referenzzähler?



  • Wie oft wird has<>() denn aufgerufen? Wenn ich das so sehe, scheint der vector quasi nie mehr als 100 Elemente haben. Das sollte ja trotz dynamic_cast recht flott gehen. Ich muss eine solche Schleife 1000000 mal durchlaufen für 5 Sekunden Laufzeit. (Und da wird jedes Mal bis 100 gerannt.)
    Insofern wäre es vielleicht leichter die Zahl der Aufrufe zu minimieren. Ansonsten hier eine Idee Edit: Oh, ich glaube das hattest du schon vor. Der Vorschlag von Shade Of Mine scheint mir allerdings recht praktisch zu sein.



  • Was spricht denn jetzt gegen meinen Vorschlag von Seite 2? Die has<...> Funktion wird vom Aufwand her auf ein array indexing reduziert. Kann mir nicht vorstellen, dass es irgendwie schneller geht.



  • GorbGorb schrieb:

    Was spricht denn jetzt gegen meinen Vorschlag von Seite 2? Die has<...> Funktion wird vom Aufwand her auf ein array indexing reduziert. Kann mir nicht vorstellen, dass es irgendwie schneller geht.

    Oh, da habe ich ja schon einen Referenzzähler übersehen 😉



  • GorbGorb schrieb:

    Was spricht denn jetzt gegen meinen Vorschlag von Seite 2?

    Gefällt mir sehr gut! - Ich glaub das könnte funktionieren.


Anmelden zum Antworten