Generierung von Attributen und Funktionen basierend auf Template Parameter



  • Hallo zusammen,

    ich suche eine Möglichkeit einer Klasse verschiedene Attribut und Funktionen hinzuzufügen. Dies soll mittels einzelner Template Parameter gesteuert werden können. Siehe dazu folgenden Beispiel samt Versuche mittels SFINAE und using:

    #include<type_traits>
    
    struct EmptyPolicy {};
    
    struct Bar
    {
       int mBar;
    
       int getBar()
       {
          return mBar;
       }
    };
    
    template<bool withBar>
    class Foo : std::conditional_t<withBar, Bar, EmptyPolicy>
    {
    public:
       // Compiliert nicht für Foo<true>
       // 'mBar' : identifier not found
       //template<bool withBar_ = withBar, std::enable_if_t<withBar_, int> = 0>
       //int getBar()
       //{
       //   return mBar;
       //}
    
       // Compiliert nicht für Foo<false>
       // 'Bar': a member using - declaration can only be applied to a base class member
       // using Bar::getBar;
    };
    
    int main()
    {
       Foo<false> fooOhneBar; // Kein Bar Attribut und keine getBar() Funktion
       Foo<true> fooMitBar; // Ein Bar Attribut und die getBar() Funktion
    }
    

    Es dies überhaupt möglich mittels Template Magie?



  • Ich glaub, das passt eigentlich. Musst noch public ableiten, wenn du von außen darauf zugreifen willst.



  • @Mechanics sagte in Generierung von Attributen und Funktionen basierend auf Template Parameter:

    Ich glaub, das passt eigentlich. Musst noch public ableiten, wenn du von außen darauf zugreifen willst.

    🤦 Stimmt da hatte ich wohl ein Brett vorm Kopf. Aber was wäre die Welt nur ohne weitere Probleme:

    #include<type_traits>
    
    struct EmptyPolicy {};
    
    struct Bar
    {
    protected:
       int mBar;
    
    public:
       int getBar()
       {
          return mBar;
       }
    };
    
    template<bool withBar>
    class Foo : public std::conditional_t<withBar, Bar, EmptyPolicy>
    {
    public:
       void doStuff()
       {
          // für alle Foos
    
          if (withBar)
          {
             mBar = 0; // 'mBar' identifier not found
             // Spezial Behandlung von Foos mitBar
          }
       }
    };
    
    int main()
    {
       Foo<false> fooOhneBar;
       Foo<true> fooMitBar;
    
       fooOhneBar.doStuff();
       fooMitBar.doStuff();
    }
    

    Gibt es hier auch eine offensichtliche Lösung die ich übersehe?



  • Du hattest doch in deinem ersten Beitrag schon std::enable_if_t benutzt (du mußt das konsequent per Template-Spezialisierung ausprogrammieren).



  • Ich habs grad nicht durchgelesen, aber wenn ich die Zeile sehe

    if (withBar)

    dann denke ich an if constexpr.



  • Template-Spezialisierung wollte ich vermeiden.Legen wir mal die Glaskugeln zur Seite und geben Butter bei die Fische. Für mein Schach Programm habe ich die Klasse Board. Diese verwaltet die einzelnen Figuren, verschiedene Bitboards (Besetze Felder, Leere Felder,..), Rochaden, Zobrist Hash, usw...

    Die Klasse Board hat auch die Funktion checkmate:

    bool chess::Board::checkmate(ColorType color) const
    {
       if (!check(color)) // wenn kein Schach dann auch kein Schachmatt
          return false;
    
       // Teste alle validen Züge ob danach immer noch Schach besteht
       for (auto move : generateMoves<MOVE_GEN_TYPE::ALL, true>(*this, color))
       {
          Board copy(*this);
          copy.applyMove(move);
    
          if (!copy.check(color)) {
             return false;
          }
       }
    
       return true;
    }
    

    Für die Board Kopie werden nicht alle Attribute benötigt (z.b. kein Zobrist Hash, En Passant Informationen) da nur auf Schach geprüft wird. Darum würde ich gerne eine abgespeckte Board Version habe welche diese Eigenschaften nicht hat und diese bei Board.appyMove nicht aktualisisert. Meine applyMove Funktion hat ca. 120 Zeilen und diese in N verschieden Template-Spezialisierungen zu haben finde ich nicht schön 😞 .

    Zu constexpr 😞 :

    if constexpr (withBar) // 'mBar': identifier not found
       ...
    


  • Aber warum auf Basis von Templates? Das liest sich für mich, als ob du "over engeneering" betreibst.
    Kannst du nicht einfach die Klassenstruktur umdrehen, d.h. ExtendedBoard erbt von Board (oder wie auch immer du die Klassen dann benennst) und hat dann die zusätzlichen Eigenschaften (Hash, En Passent, etc.)?



  • @Th69 sagte in Generierung von Attributen und Funktionen basierend auf Template Parameter:

    Aber warum auf Basis von Templates? Das liest sich für mich, als ob du "over engeneering" betreibst.
    Kannst du nicht einfach die Klassenstruktur umdrehen, d.h. ExtendedBoard erbt von Board (oder wie auch immer du die Klassen dann benennst) und hat dann die zusätzlichen Eigenschaften (Hash, En Passent, etc.)?

    Das mit dem "over engeneering" lasse ich gerne gelten, aber da es nur ein privates Projekt ist und mich die Machbarkeit an dieser Stelle interessiert 😇 .
    Der Charme an der Template Lösung wäre die Konfigurierbarkeit. Ich brauche z.B. ein Board nur mit Hash, kein Problem einfach nur Template Parameter setzen 🙂 . Anstatt eine neue Klasse schreiben zu müssen.

    Wenn es leider nicht möglich ist nur eine applyMove Funktion zu habe werde ich wohl die benötigten Template-Spezialisierungen anlegen müssen 😞 .


Log in to reply