GCC Template instanzen anschauen



  • Ja du hast wohl Recht.

    Kennst Du zufällig ein gutes Tutorial für Variadic Templates ??
    Hab mir schon einige angeschaut, und auch einiges verstanden... aber so ganz auf einen Nenner gerbracht habe ich das noch nicht...


  • Mod

    In welchem Sinne? Wie man sie benutzt? Ich dachte du wolltest irgendwie selber einen Compiler dafür schreiben und wolltest deswegen einen Einblick in die Compilerstrukturen des gcc.

    Was stört dich denn an den Suchergebnissen bei Google?



  • Ich möchte gerne eine template klase haben,
    z.b.:

    template <typename T1, size_t D>
    class leaf
    {
    
    public:
     leaf(...)  /// Hier sollen nun D * T1 argumente übergeben werden.
                /// Das soll typensicher geschehen... 
    
    private:
    
    };
    
    /// z.B.
    leaf<double,3> _leaf(0.0,1,0.2);  /// Soll leaf(double,double,double) aufrufen
    

    Also der code soll lediglich die Funktionalität rüberbringen...
    Ich würds gerne explizit mit variadic templates versuchen...
    Einfach zum schauen ob sich eine gute lösung raus kristallisiert, sonst mach ich das eben anderst..



  • Okay, habs... =)... wobei ich mir noch nicht ganz drüber im Klaren bin wiso das geht muss ich sagen (also wie es abläuft schon, aber eben wie die typensicherheit erreicht wird), von daher wärs schön wenn jemand mal drüber schaut.

    template <typename T1,size_t D>
    class leaf
    {
      public:
        template<typename ...T2>
        leaf(T1 val,T2... args);
    
        leaf(T1 val);
    
      private:
    
    };
    
    template <typename T1, size_t D>
    template<typename ...T2>
    leaf<T1,D>::leaf(T1 val, T2... args)
    {
        std::cout <<"\nval\t" << val <<"typeid(val)" << typeid(val).name() <<"\ttypeid(double)" <<typeid(double).name();
        leaf<T1, D>(args...);
    }
    
    template <typename T1, size_t D>
    leaf<T1,D>::leaf(T1 val)
    {
        std::cout <<"\nval\t" << val <<"typeid(val)" << typeid(val).name() <<typeid(double).name();
    }
    

    Also wie man sieht ist das noch tnicht fertig, aber in einer form wo was werden könnte...
    Bin mir allerdings nicht drüber im Klaren, wie die typensicherheit erreicht wird.

    Also ein

    leaf<int,3> _leaf(0.0 , (double) 1 , 0.0 , 1.0 , 1.234); /// Lauter ints
    leaf<double,3> _leaf(0.0 , (int) 1 , 0.0 , 1.0 , 1.234); /// lauter double
    

    Wobei klaro die Funktionsaufrufe noch so oft geschehen, wie Parameter übergeben werden, kein const etc.... aber das müßt nachträglich leicht sein...

    EDIT:
    Das T2 Parameter-pack kann doch eigentlich alles sein. Also sowohl {int,double,char,...}. Nur weil es dann an den T1 mit festem Typ übergeben wird,
    heißt das doch noch lange nicht, dass die sachen dann auch als T1 typ auf den stack geschmissen werden.
    Ich hätte erwartet, dass bei

    leaf<double,3> _leaf(0.0 , (int) 1 , 0.0 , 1.0 , 1.234); /// lauter double
    

    der int 1 als double interprätiert wird....



  • 1. Ich würde das mit einer static-Funktion und nicht mit einem Konstruktor machen (aber das war ja nur ein Versuch).
    2. D solltest du nicht brauchen, da du variadic templates sowieso rekursiv abarbeiten musst.
    3. Bist du wirklich sicher, dass das Ding als int interpretiert wird? Das würde mich wundern.
    4. Probier's doch mal mit leaf(T1 val, T1... args). Bin mir allerdings nicht 100% sicher, ob's geht.



  • Hi,

    also angefangen habe ich wie du sagst mit

    leaf(T1 val, T1... args).
    

    Das scheint logisch...
    Das funktioniert aber nicht...

    Auf >Grund des Fehlers,wollte ich es zum laufen bringen, und siehe da, es lief und zu meinem erstaunen sogar typenrichtig.

    Also wenn doubles und ints für meine ausgewählten Zahlen nicht zufällig die selbe Binärdarstellung haben, gehts....

    Ich gebe immer ein "T1 val" aus, in so fern ist die interprätation immer
    die des Typs T1. und die ist bie

    leaf<double,3> _leaf(0.0 , (int) 10 , 0.0 , 1.0 , 1.234);
    

    ein double
    und bei

    leaf<int,3> _leaf(0.0 , (int) 10 , 0.0 , 1.0 , 1.234);
    

    eben int.

    Ich bekommebisjetzt für alle im konstruktor angegebenen Werte die richtigen
    Ausgaben ....

    Das heißt für mich es geht.

    Wundern tut es mich aber genauso...

    P.s. :
    Die sonstigen Parameter sind für andere Dinge vorgesehen, und werden schon benötigt.... sind hier aber nicht von Bedeutung...
    Dan geht es mir schon explizit um den Konstruktor... nicht um eine andere Funktion. Deswegen dann später auch das "D", damit ich die Anzahl der Parameter beschränken kann...



  • Ich glaube ich habe es jetzt verstanden,

    es funktioniert so, dass die Parameterliste eben aus der Summe der einzelnen primärtypen ( bei mir eben immer double) geblidet wird.

    Wieviele bytes dann nach links übergeben werden sagt der typ von T1 und das ist eben immer genau ein double...

    Das läuft immer richtig so 🙂

    Gleile Sache 🙂



  • Kannst du bitte nochmal erklären, was ausgegeben wird, was du willst und was dich wundert?
    Oder funktioniert alles so, wie es soll?



  • Es funktioniert alles wie es soll.
    Also die Funktionalität im Programm schein fertig, oder ist für alle von mir
    versuchten Werte richtig.

    Ich hatte bis gerade eben aber nicht verstanden wiso es funktioniert.
    Vor zwei sekunden ist aber der Kroschen gefallen.
    Gepostet habe ich, weil ich nicht wußte wiso das so glatt läuft.

    Ich habe jetzt aber eine Vorstellung entwickelt, und werde die mal überprüfen.
    Bin sehr zuversichtlich, dass es so läuft wie ich mir das vorstelle.

    wobei natürlich das short

    leaf<double,3> _leaf(0.0 , (short) 10.01 , 1.1 , 1.0 , 1.234);
    

    nach eienr double 10 gecastet wird.



  • Okay, habs fast aber noch nicht ganz...

    Wenn ich ein leaf vom typ double erstelle

    leaf<double,3> _leaf(....
    

    und dann auf den Stack typen mit unterschiedlichen größen schmeiße.
    z.B.

    leaf<double,3> _leaf( float,short,char etc)
    

    also Typen deren Größe anderst ist, als die von T1 = double.

    Wie funktioniert das aufklappen des stacks.

    Und was macht er, wenn ich plötzlich eine struct oder eine Klasse übergebe ??



  • Die Typen werden beim rekursiven Aufruf der Funktion automatisch konvertiert. Da du irgendwann mal ein leaf<double, 3 /* sollte da nicht 2 rein? />(double / schon konvertiert von short */, char) aufrufst, ruft dieses dann entsprechend leaf<double, 3>(char) auf, und da der Typ immer T1 sein muss, wird char halt nach double konvertiert. Von Speicher ist da gar keine Rede mehr.



  • Also der leaf dimensionsparameter ist frei wählbar, sonst wäre der Aufwand ja total doof und für die Katz...

    Ich hoffe eine Speicherandordnung zu finden, wo ich
    n-Dimensionale Daten mit 3d-Now/mmx effizienter binärsuchen kann.

    Oder ich möchte die Konvergenz (zeitlich) parallel für möglichst viele Dimensionen, je nach dem wie groß der zu suchende Typ eben ist und wie oft ich den typ auf einmal in die Prozessorregister bekomme.

    Am liebsten in einem Array, aber das wird wohl nix.
    Deswegen hier die leafs...
    Wobei man eigentlich sowas wie ne eigene Speicherverwaltung machen kann, und
    dann der sagen, wie der Speicher angefordert werden soll, also dass er in einem Stück bleibt für die ganze klasse zum beispiel (eben das Auslagerungsproblem in den Griff bekommen) und dann immer placement new...

    Den Speicher würde ich bei C/C++ nie vergessen, der gehört da dazu wie Butter bei de Fische =)...
    Ich glaube wenn man den Speicher bei C/C++ nicht im Blick hat, dann wirds kritisch..

    Ich denke aufgerollt liegt im Stack dann ein array wie

    leaf<double,3> _leaf( (char), (short), (int))
    
    /// -> wird zu: char [sizeof(char)+sizeof(short)+sizeof(int)] /// im stack
    /// Und dann muss beim unroll erste Rekursion
    /// -> T1 val = (double) ???<- ist ein char und es verbleibt 
    /// char [sizeof(short)+sizeof(int)] 
    /// etc...
    

    Jetzt ist natürlich die Frage, wo ich auf den casting mechanismus zugreifen kann. Man könnte dann auch eigene typen casten.


Anmelden zum Antworten