Spezialisierung einer Listenklasse



  • ich möchte ein Liste (one to many Beziehung) für meinen ORM Bibliothek erstellen. 1 zu N Beziehungen können ja mit oder ohne Relationstabelle realsiert werden:

    Dazu würde ich gerne eine Lösung implementieren, die via Template Parameter entscheidet, ob eine eigene Relationstabelle angelegt wird oder nicht. Mein Ansatz ist, wenn ich die Set-Methode des Rückwärtslink angebe, soll keine Relationstabelle erzeugt werden. (Wie die Relationstabelle erzeugt wird, spielt hier keine Rolle)

    Kurz, ich benötige eine Klassen-Template-Spezialisierung:

    Pseudo Code Beispiel:

    // Entitäten
    class address
    {
      string street;
      int number;
      // ..
    
      void resident(const person &p) { resident = p }
    
      person resident;
    }
    
    class person
    {
      string name;
    
      // mit Relationstabelle
      list<address, person> addresses;
    
      // ohne Relationstabelle
      list<address, person, &address::resident> addresses;
    }
    

    Hier mein Ansatz zur Spezialisierung

    // Liste
    template < class S, class T >
    class list { ... }
    
    // Spezialisierte Liste
    template < class S, class T, void (T*::set_func)(const S&) >
    class list { ... }
    

    Leider habe ich noch keine Lösung für diese Spezialisierung gefunden. Hat jemand vielleicht einen Tipp für mich?

    Besten Dank!



  • Ok, dass mit der Spezialisierung über die Memberfunktion geht wohl nicht so einfach. Deshalb werde ich über ein bool die Spezialisierung machen. (Wenn nicht noch einer mit 'ner coolen Idee um die Ecke kommt)

    Gruß
    zussel


  • Mod

    C++11 zur Rettung!

    template <typename T1, typename T2, void (T1::* ...FUNC)(const T2&)> struct list; // Allgemeine Version, wird nie definiert
    template <typename T1, typename T2> struct list<T1, T2> { };  // Partielle Spezialisierung für 2 Argumente...
    template <typename T1, typename T2, void (T1::*FUNC)(const T2&) > struct list<T1, T2, FUNC> { };  // ... und für drei Argumente
    
    #include <string>
    
    class person;
    class address
    {
      std::string street;
      int number;
    public:
      void resident(const person &p);
     };
    
    class person
    {
      std::string name;
    
      // mit Relationstabelle
      list<address, person> addresses1;
    
      // ohne Relationstabelle
      list<address, person, &address::resident> addresses2;
    };
    

    P.S.: Es wäre übrigens ganz angenehm, wenn du Codebeispiele etwas "korrekter" geben würdest, so dass man nicht erst 15 Semikolons setzen braucht, wenn man von deinem Code ausgehend eine Lösung zeigen möchte.



  • Oh, das sieht ja gut aus! Vielen Dank! Hatte diese Variante auch versucht, aber ohne die allgemeine Version.

    Vielleicht kannst Du mir kurz erklären, wobei die allgemeine Version hier hilft.

    Und: Versprochen, meine nächsten Code Schnippsel werden korrekt sein! 🙂

    Gruß,
    zussel



  • Ok, habs verstanden. Durch das variadic template könnte ich 0 bis n Memberfunktionen übergeben. Und eine Spezialisierung hat 0 (keine) und die andere 1 (eine) Memberfunktion als Parameter.


  • Mod

    SeppJ schrieb:

    C++11 zur Rettung!

    Oder ein Defaultargument

    template <typename T1, typename T2, void (T1::* FUNC)(const T2&) = 0> struct list; // zwei oder drei Argumente
    template <typename T1, typename T2> struct list<T1, T2> { };  // Partielle Spezialisierung für 2 Argumente...
    

  • Mod

    camper schrieb:

    SeppJ schrieb:

    C++11 zur Rettung!

    Oder ein Defaultargument

    Argh! Irgendwie hatte ich ein Defaultparameter am Anfang im Hinterkopf (bei Typen würde man ja void* nehmen) und nicht dran gedacht, dass Pointer schließlich auch einen besonderen Nullwert haben dürfen. Aber dann sind irgendwie die C++11-Pferde mit mir durchgegangen und ich wollte unbedingt die variadic-template Lösung zum Funktionieren bringen (es dauert eine Weile bis man hier auf die richtige Syntax kommt 😉 ).



  • Mit einem Default Argument hatt eich auch schon rum gespielt. Hatte aber nicht funktioniert - da es nicht 0 war. Manchmal ist eine Lösung so einfach. Ein Pointer auf eine Funktion kann auch Null sein.

    Vielen Dank für eure Lösungsvorschläge. Das hat mir wirklich weiter geholfen.

    Auch wenn die Lösung mit den Variadic Templates c++11 State of the Art ist, so werde ich doch erstmal mit dem Defaultargument arbeiten und sehen, wie weit ich damit komme.

    Danke,
    zussel



  • Hab die Variante mit dem Defaultwert jetzt mal ausprobiert und mein Compiler meckert:

    list.cpp:89:44: error: type ‘void (T1::*)(const T2&)’ of template argument ‘0’ depends on template parameters
    

    Die zweite Zeile mag er nicht:

    template <typename T1, typename T2, void (T1::* FUNC)(const T2&) = 0> struct list;
    template <typename T1, typename T2> struct list<T1, T2> { };
    

    Anscheinend mag der keinen Defaultwert. Mein Compiler ist:

    g++ (GCC) 4.7.2
    

    Keine Compilerargumente.



  • Muss den Thread nochmal hoch pushen.

    Leider konnte ich keine Lösung für den Defaultwert des Funktionspointers finden, daher bin ich zunächst nochmal den Weg mit den Variadic Templates gegangen.

    Jetzt stehe ich aber vor dem nächsten Problem: Was ist, wenn ich einen builtin Typ ebenfalls ermöglichen möchte (z.B. einen int).

    template <typename T1, typename T2, void (T1::* ...FUNC)(const T2&)> struct list; // Allgemeine Version, wird nie definiert
    template <typename T1, typename T2> struct list<T1, T2> { };  // Partielle Spezialisierung für 2 Argumente...
    template <typename T1, typename T2, void (T1::*FUNC)(const T2&) > struct list<T1, T2, FUNC> { };  // ... und für drei Argumente
    
    #include <string>
    
    class person;
    class address
    {
      std::string street;
      int number;
    public:
      void resident(const person &p);
     };
    
    class person
    {
      std::string name;
    
      // NEU: builtin type
      list<int, person> integers;
    
      // mit Relationstabelle
      list<address, person> addresses1;
    
      // ohne Relationstabelle
      list<address, person, &address::resident> addresses2;
    };
    

    Natürlich meckert hier der Compiler, dass er für einen builtin Typ keinen Funktionspointer anlegen kann. jetzt überlege ich, wie man die allgemeine Version dahingehend erweitern kann, dass sie auch bei builtins funktioniert.

    Leider kann man ja keine "Template Erweiterung" machen, sondern nur eine Spezialisierung 😞

    @camper und SeppJ: habt ihr noch einen guten Einfall?

    EDIT: Es ist auch OK, wenn das Ergebnis ist, dass das so nicht geht!

    Gruß,
    zussel

    BTW: Wenn man eine eigene Bibliothek schreibt und einen Listenklasse anbietet möchte, die die gleiche Schnittstelle bietet, wie die STL Liste, ist es dann ok, wenn man diese Klasse auch "list" nennt (natürlich in einem eigenen Namspace).


Anmelden zum Antworten