Absolute Typgrößen mit templates



  • Dein Ansatz ist nicht so viel anders wie meiner, ich habe die typelist allgemein gehalten und du hast eine speziell für den Zweck geschrieben.

    Finde deinen Ansatz prinzipiell sehr nett, aber es wäre schon, wenn du die maximale Größe automatisch ermitteln würdest, so wird das Ändern leider nen bischen zum Gefrickel.

    Bei mir ist es das derzeit zwar auch, aber ich finde diese Art von Typliste schöner, als die Rekursive, welche man zwangsweise mit nem Makro erstellen muss um den Überblick zu behalten (wird bei Loki verwendet).

    Den Find-Algo habe ich bei mir speziell für den TypeWrapper ausgelegt, das sollte auch noch verallgemeinert werden. BitsToType existiert eigentlich auch nur noch um den Sinn des ganzen zu untermauern, da ein Find leider nicht so aussagekräftig ist.

    Werde mich Morgen wohl hinsetzen und nochmal ne neue (größere) Typliste schreiben und schauen ob ich nen allgemeinen Find-Algo hinbekomme. Deine Idee mit dem überladen der Größen anhand von signed und unsigned gefällt mir, so könnte ich bei mir die zweite Typliste streichen 🙂



  • Ach eines hab ich ganz vergessen, wenn bei dir ein Typ nicht existiert, dann ist die Fehlermeldung weniger verwirrend wie bei meiner Version.
    Das muss ich bei mir auch noch ändern, aber wie gesagt will das ganze eh nochmal frisch machen, mit ner Typliste ist das eigentliche Problem bzw. Vorhaben eh keine Schwierigkeit mehr 🙂



  • Hier ist noch ein anderer Ansatz

    struct Tail{};
    template<class TElement, class TNext>
    struct  List{
    	typedef TElement Element;
    	typedef TNext Next;
    };
    
    typedef List<signed char, List<signed short, List<signed int, List<signed long, Tail> > > > SignedIntegerList;
    typedef List<unsigned char, List<unsigned short, List<unsigned int, List<unsigned long, Tail> > > > UnsignedIntegerList;
    
    template<bool yesno, class TTrue, class TFalse>
    struct IfElse;
    
    template<class TTrue, class TFalse>
    struct IfElse<true, TTrue, TFalse>{
    	typedef TTrue Result;
    };
    
    template<class TTrue, class TFalse>
    struct IfElse<false, TTrue, TFalse>{
    	typedef TFalse Result;
    };
    
    template<int bytes, class TFrom = UnsignedIntegerList>
    struct SelectInteger{
    	typedef
    	  typename IfElse<
    	    sizeof(typename TFrom::Element)==bytes,
    	    typename TFrom::Element,
    	    typename SelectInteger<bytes, typename TFrom::Next>::Result
    	  >::Result Result;
    };
    
    template<int bytes>
    struct SelectInteger<bytes, Tail>{
    	typedef void Result;
    };
    

    Erscheint mir etwas einfacher als die bisherigen Ansätze. Die Fehlermeldung des GCC ist eine Zeile groß in der er ausdrückt, dass er keine "void" Variable anlegen kann. Sollte als Fehlermeldung doch recht einfach zu verstehen sein.



  • Hier das ganz noch einmal in einer überarbeiteten Version die viel allgemeiner gehalten ist. Desweiteren ist sie besser gegliedert. Sollte also leichter verständlich sein.

    //////////////////////////
    //
    //    IfElse
    //
    template<bool yesno, class TTrue, class TFalse>
    struct IfElse;
    
    template<class TTrue, class TFalse>
    struct IfElse<true, TTrue, TFalse>{
    	typedef TTrue Result;
    };
    
    template<class TTrue, class TFalse>
    struct IfElse<false, TTrue, TFalse>{
    	typedef TFalse Result;
    };
    
    //////////////////////////
    //
    //    TypeList
    //
    struct TypeListTail{};
    template<class TElement, class TNext>
    struct  TypeList{
    	typedef TElement Element;
    	typedef TNext Next;
    };
    
    //////////////////////////
    //
    //    Default integer type lists
    //
    typedef TypeList<signed char, TypeList<signed short, TypeList<signed int, TypeList<signed long, TypeListTail> > > > SignedIntegerList;
    typedef TypeList<unsigned char, TypeList<unsigned short, TypeList<unsigned int, TypeList<unsigned long, TypeListTail> > > > UnsignedIntegerList;
    
    //////////////////////////
    //
    //    Select Type
    //
    template<class TCondition, class TFrom>
    struct SelectType{
    	typedef
    	  typename IfElse<
    	    TCondition::template Evaluate<typename TFrom::Element>::result,
    	    typename TFrom::Element,
    	    typename SelectType<TCondition, typename TFrom::Next>::Result
    	  >::Result Result;
    };
    
    template<class TCondition>
    struct SelectType<TCondition, TypeListTail>{
    	typedef void Result;
    };
    
    //////////////////////////
    //
    //    Size condition
    //
    template<int bytes>
    struct SizeCondition
    {
    	template<class T>
    	struct Evaluate{
    		static const bool result = (sizeof(T) == bytes);
    	};
    };
    
    //////////////////////////
    //
    //    TypeListUnion
    //
    template<class TTypeListA, class TTypeListB>
    struct TypeListUnion
    {
    	typedef typename TypeListUnion<
    	  typename TTypeListA::Next,
    	  TypeList<typename TTypeListA::Element, TTypeListB>
    	>::Result Result;
    };
    
    template<class TTypeListB>
    struct TypeListUnion<TypeListTail, TTypeListB>
    {
    	typedef TTypeListB Result;
    };
    
    //////////////////////////
    //
    //    SizeInteger
    //
    struct SelectIntegerSign{
    	enum{
    		unimportant,
    		no_sign,
    		sign
    	};
    };
    
    template<int bytes, int has_sign = SelectIntegerSign::unimportant>
    struct SelectInteger;
    
    template<int bytes>
    struct SelectInteger<bytes, SelectIntegerSign::no_sign>
    {
    	typedef typename SelectType<SizeCondition<bytes>, UnsignedIntegerList>::Result Result;
    };
    
    template<int bytes>
    struct SelectInteger<bytes, SelectIntegerSign::sign>
    {
    	typedef typename SelectType<SizeCondition<bytes>, SignedIntegerList>::Result Result;
    };
    
    template<int bytes>
    struct SelectInteger<bytes, SelectIntegerSign::unimportant>
    {
    	typedef typename SelectType<
    	  SizeCondition<bytes>,
    	  typename TypeListUnion<UnsignedIntegerList, SignedIntegerList>::Result
    	>::Result Result;
    };
    
    //////////////////////////
    //
    //    Example
    //
    int main()
    {
    	SelectInteger<1>::Result a;
    	SelectInteger<2, SelectIntegerSign::sign>::Result b;
    	SelectInteger<4, SelectIntegerSign::no_sign>::Result c;
    
    	typedef TypeList<unsigned long long, UnsignedIntegerList> UnsignedIntegerListWithLL;
    	SelectType<SizeCondition<8>, UnsignedIntegerListWithLL>d;
    }
    


  • Ben04 schrieb:

    Die Fehlermeldung des GCC ist eine Zeile groß in der er ausdrückt, dass er keine "void" Variable anlegen kann. Sollte als Fehlermeldung doch recht einfach zu verstehen sein.

    Mach es trotzdem so wie ich, nimm eine leere Struktur und mach sie privat. Du solltest nämlich nicht vergessen, dass es da noch void* gibt.

    Zudem versteh ich nicht ganz, wozu dein SelectIntegerSign::unimportant gut sein soll. Wenn ich das richtig sehe, sind solche Typen doch immer unsigned.



  • Zudem versteh ich nicht ganz, wozu dein SelectIntegerSign::unimportant gut sein soll. Wenn ich das richtig sehe, sind solche Typen doch immer unsigned.

    An sich ja. Die Idee war zu zeigen wie man aus 2 Listen auswählen kann. Der Code ist ja auch so gehalten, dass es leicht ist einen Type zu suchen der andere Bedingungen erfüllt. SelectIntegerSign::unimportant ist also in der Tat überflüssing.



  • hola

    interessante thematik hier. blick zwar noch net so ganz durch, aber sieht interessant aus.
    hab mir nun bissl den kopf zerbrochen wie man ohne dem CHAR_BIT aus der limits.h die bits pro bytes rausbekommen koennte. weiß nur net ob das nun so korrekt is.

    template <unsigned char x, int z = 1>
    class count_bits
    {
       public:
          enum { value = z + count_bits<x >> 1,1>::value };
    };
    
    template <int z>
    class count_bits<0,z>
    {
       public:
          enum { value = 0 };
    };
    
    const unsigned char full_byte = ~0;
    int bits_pro_byte = count_bits<full_byte>::value;
    

    scheinbar funktioniert es auch richtig. aber vielleicht kann man das ja auch noch besser loesen.
    die konstante full_byte hab ich deshalb benuetzt, weil mein BCB meckert wenn ich count_bits direkt ~0 uebergebe.
    Vielleicht kann mir ja jemand sagen, warum das so ist.

    Meep Meep



  • Probiers mit einem Cast, das könnte die Warnung des BCB beseitigen.

    int bits_pro_byte = count_bits<~(unsigned char)(0)>::value;
    

    Allerdings wundert es mich, dass es überhaupt kompiliert. Wahrscheinlich hat da jeder Compiler seine eigene Vorstellung von der Syntax Überprüfung. Mach deshalb noch Klammern in dein Template, dann sollte es überall funktionieren.

    enum { value = z + count_bits<(x >> 1),1>::value };
    

    Und bitte verwende static const, enum ist ein Hack und sollte heute nicht mehr verwendet werden. Wer sich mit Template Metaprogrammierung beschäftigt, für den sind sowieso nur aktuelle Compiler von Interesse und die sollten mittlerweile auch static const für in-class Initialisierung beherrschen.
    Ausserdem kann enum hier Probleme bereiten, zB wenn die interne Darstellung auf einer Plattform genauso gross ist wie ein char.



  • So, ich habe gestern nochmal mit den geposteten Sachen etwas rumgespielt und dies ist nun meine finale Version:

    // wieviel Bit hat ein Byte?
    template <unsigned char Value, size_t N>
    struct compute_bits_per_byte
    {
    	static const size_t result = compute_bits_per_byte<(Value >> 1), N + 1>::result;
    };
    
    template <size_t N>
    struct compute_bits_per_byte<0, N>
    {
    	static const size_t result = N;
    };
    
    // Bit-Version von sizeof
    #define bit_sizeof(x) (sizeof(x) * compute_bits_per_byte<~(unsigned char)(0), 0>::result)
    
    //
    template <class T, class Next>
    struct type_list
    {
    	typedef T type;
    	typedef Next next;
    };
    
    //
    template <bool Condition, class Then, class Else>
    struct if_then_else;
    
    template <class Then, class Else>
    struct if_then_else<false, Then, Else>
    {
    	typedef Else result;
    };
    
    template <class Then, class Else>
    struct if_then_else<true, Then, Else>
    {
    	typedef Then result;
    };
    
    //
    template <size_t Size, class Element>
    struct select_type
    {
    private:
    	typedef typename if_then_else<
    		Size == bit_sizeof(typename Element::type),
    		Element,
    		select_type<Size, typename Element::next>
    		>::result tmp;
    public:
    	typedef typename tmp::type type;
    };
    
    template <size_t Size>
    struct select_type<Size, void>
    {
    // Compilefehler falls kein Typ gefunden
    private:
    	struct type
    	{
    	};
    };
    
    template <bool Signed>
    struct integer_types;
    
    template <>
    struct integer_types<false>
    {
    	typedef
    		type_list<unsigned char,
    		type_list<unsigned short,
    		type_list<unsigned int,
    		type_list<unsigned long,
    		type_list<unsigned long long,
    		void
    		> > > > > content;
    };
    
    template <>
    struct integer_types<true>
    {
    	typedef
    		type_list<signed char,
    		type_list<signed short,
    		type_list<signed int,
    		type_list<signed long,
    		type_list<signed long long,
    		void
    		> > > > > content;
    };
    
    template <size_t Size, bool Signed>
    struct select_integer
    {
    	typedef typename select_type<Size, typename integer_types<Signed>::content>::type result;
    };
    
    typedef
    	type_list<float,
    	type_list<double,
    	type_list<long double,
    	void
    	> > > floating_point_types;
    
    template <size_t Size>
    struct select_floating_point
    {
    	typedef typename select_type<Size, floating_point_types>::type result;
    };
    
    // Bsp
    typedef select_integer<16, false>::result uint16;
    

    Wer Lust hat, kann damit auch Gleitkommatypen definieren. 🙂



  • Ah wie ich sehe sind meine Mitstreiter immer noch fleißig an der Sache dran. Habe selber in letzter Zeit leider keine Zeit mehr gehabt, da die Schule wieder angefangen hat und ich gerade im totalen Prüfungsstress bin, aber diese Woche sind die letzten Klausuren, danach habe ich wieder Zeit und werde mich auch daran setzen.

    Wobei ich, wie früher schon erwähnt, mehr auf die Typliste als auf das ursprüngliche Vorhaben konzentrieren.


Anmelden zum Antworten