Frage zu boost



  • Okay, der Titel ist etwas unspezifisch, aber:
    Gibt es in boost etwas, das folgendes leistet:

    template<typename A, typename B>
    Präziserer_Fundamenteler_Typ<A,B>::type function(A & a, B & B)
    {
       //...
    }
    

    😕

    Nochmal als Text:
    Ich bräuchte etwas, das mir von zwei (fundamentalen) Typen den größeren bzw. präziseren Typen ermittelt und zur Verfügung stellt. Ich meine, dass sowas in boost drin ist, aber ich kann es irgendwie nicht finden.

    Danke im Voraus. :p



  • Eventuell wirst du in der numeric_conversion lib fündig. Sonst müsstest du dir mit den typetrais selber was zusammenschrauben.
    http://www.boost.org/doc/libs/1_40_0/libs/numeric/conversion/index.html


  • Mod

    Könnte man da nicht recht einfach was mit limits selber machen? Ungefähr so:

    template <bool Condition, typename TrueResult, typename FalseResult>
    class if_;
    
    template <typename TrueResult, typename FalseResult>
    struct if_<true, TrueResult, FalseResult>
    {
      typedef TrueResult result;
    };
    
    template <typename TrueResult, typename FalseResult>
    struct if_<false, TrueResult, FalseResult>
    {
      typedef FalseResult result;
    };
    
    int main() 
    {
      if_< (numeric_limits<int>::digits > numeric_limits<short>::digits) , int, short>::result number(3);
    }
    

    Das Ganze halt noch in ein Template verpackt und geprüft, ob es sich auch um fundamentale Typen handelt.



  • SeppJ schrieb:

    Könnte man da nicht recht einfach was mit limits selber machen? Ungefähr so:

    template <bool Condition, typename TrueResult, typename FalseResult>
    class if_;
     
    template <typename TrueResult, typename FalseResult>
    struct if_<true, TrueResult, FalseResult>
    {
      typedef TrueResult result;
    };
     
    template <typename TrueResult, typename FalseResult>
    struct if_<false, TrueResult, FalseResult>
    {
      typedef FalseResult result;
    };
    
    int main() 
    {
      if_< (numeric_limits<int>::digits > numeric_limits<short>::digits) , int, short>::result number(3);
    }
    

    Das Ganze halt noch in ein Template verpackt und geprüft, ob es sich auch um fundamentale Typen handelt.

    Sicher kann man das selbst machen. Aber wieso soll man das Rad neu erfinden, wenn es eh schon z.B. in boost drin ist?



  • Ich hätte mal einen Vorschlag. Der Einfachheit halber habe ich mal ein paar Typen nach Genauigkeit sortiert, wäre natürlich besser, wenn du dich an den Werten in <climits> orientierst. Ein paar Typen ( unsigned z.B.) fehlen auch:

    template <typename T>
    struct type_precision
    {
    
    };
    
    #define SPECIALIZE_TYPE_PRECISION(TYPE, VALUE)  \
    template <>                                     \
    struct type_precision<TYPE>	                 \
    {                                               \
    	static const int value = VALUE;             \
    }
    
    SPECIALIZE_TYPE_PRECISION(char, 10);
    SPECIALIZE_TYPE_PRECISION(wchar_t, 20);
    SPECIALIZE_TYPE_PRECISION(short, 30);
    SPECIALIZE_TYPE_PRECISION(int, 40);
    SPECIALIZE_TYPE_PRECISION(long, 50);
    SPECIALIZE_TYPE_PRECISION(float, 60);
    SPECIALIZE_TYPE_PRECISION(double, 70);
    SPECIALIZE_TYPE_PRECISION(long double, 80);
    
    template <typename T, typename U, bool EXPR>
    struct most_precise_arithmetic_helper
    {
    	typedef T type;
    };
    
    template <typename T, typename U>
    struct most_precise_arithmetic_helper<T, U, false>
    {
    	typedef U type;
    };
    
    template <typename T, typename U>
    struct most_precise_arithmetic
    {
    	static const bool first_type = type_precision<T>::value > type_precision<U>::value;
    	typedef typename most_precise_arithmetic_helper<T, U, first_type>::type type;
    };
    

    Die Metafunktion most_precise_arithmetic ist das eigentlich Wichtige. Weiss vielleicht gerade jemand, warum ich einen Syntaxfehler wegen der Klammer erhalte, wenn ich direkt schreibe:

    typedef typename most_precise_arithmetic_helper<T, U, 
    	 (type_precision<T>::value < type_precision<U>::value) >::type type;
    

    Hm, ging wohl etwas lange, SeppJ kam mir zuvor. Seine Möglichkeit ist auch etwas einfacher, aber vielleicht hilft ja meine trotzdem etwas. 🙂



  • Nochmal: Wie man das selbst bastelt, ist mir grundsätzlich klar. Nur habe ich keinen Bock dazu, wenn es das schon fertig geben sollte.

    Trotzdem danke Euch für die Mühe. 👍



  • Tachyon schrieb:

    Nochmal: Wie man das selbst bastelt, ist mir grundsätzlich klar. Nur habe ich keinen Bock dazu, wenn es das schon fertig geben sollte.

    Sorry, hab deinen Beitrag vorhin noch nicht gesehen.

    Vielleicht helfen unsere Vorschläge ja sonst jemandem, der über diesen Thread stolpert (obwohl meine Lösung zugegebenermassen nicht sehr schön ist). 😉


  • Mod

    Tachyon schrieb:

    Nochmal: Wie man das selbst bastelt, ist mir grundsätzlich klar. Nur habe ich keinen Bock dazu, wenn es das schon fertig geben sollte.

    Trotzdem danke Euch für die Mühe. 👍

    Also mindestens eine if Bedingung gibt es schon im Metaprogrammierungsteil. Ob es da auch eine Spezialisierung auf Typpräzision gibt, weiß ich jetzt aber auch nicht.



  • Ich weiß nicht, ob's bei Boost was in der Richtung gibt. Aber im kommenden C++0x wird es den Header <type_traits> geben, der u.a. auch das variadische Template "common_type" beinhaltet:

    typedef common_type<int,short,float>::type dings; // dings = float

    Ich wüsste nicht, wie man C++03-Mitteln an den "common type" drankommt, ohne manuell zig Spezialisierungen anlegen zu müssen.

    Gruß,
    SP



  • Auf den ersten Blick sieht auch
    boost::numeric::conversion_traits<T, S>
    ganz gut aus...

    bb



  • unskilled @logged-off schrieb:

    Auf den ersten Blick sieht auch
    boost::numeric::conversion_traits<T, S>
    ganz gut aus...

    bb

    Ne, leider nicht. Das ist eher zum konvertieren von S->T, sucht aber nicht den "passenderen" Typen aus.

    Ich habe mal was zusammengehackt. Bin mir noch nicht so ganz sicher, ob die Regeln wirklich das abdecken, was ich brauche, aber bis jetzt scheint es einigermaßen zu funktionieren:

    template<bool, typename TrueType, typename FalseType>
    struct ConditionSwitch;
    
    template<typename TrueType, typename FalseType>
    struct ConditionSwitch<true, TrueType, FalseType>
    {
        typedef TrueType type;
    };
    
    template<typename TrueType, typename FalseType>
    struct ConditionSwitch<false, TrueType, FalseType>
    {
        typedef FalseType type;
    };
    
    template<typename A, typename B>
    struct CheckIfSameCategory
    {
        enum{value = (std::numeric_limits<A>::is_integer == std::numeric_limits<B>::is_integer) };
    };
    
    template<bool, typename A, typename B>
    struct CheckPrecision;
    
    template<typename A, typename B>
    struct CheckPrecision<true, A, B>
    {
        typedef typename ConditionSwitch< (std::numeric_limits<A>::digits > std::numeric_limits<B>::digits), A, B>::type type;
    };
    
    template<typename A, typename B>
    struct CheckPrecision<false, A, B>
    {
        typedef typename ConditionSwitch< std::numeric_limits<A>::is_exact, B, A >::type type;
    };
    
    template<typename A, typename B>
    struct GetBetterType
    {
        //only arithm. types allowed
        BOOST_STATIC_ASSERT(boost::is_arithmetic<A>::value);
        BOOST_STATIC_ASSERT(boost::is_arithmetic<B>::value);
        typedef typename CheckPrecision< CheckIfSameCategory<A, B>::value, A, B>::type type;
    };
    
    int main()
    {
        {
            typedef GetBetterType<char, short>::type type;
    
            std::cout << std::boolalpha << std::numeric_limits<type>::is_exact << '\n';
            std::cout << std::numeric_limits<type>::digits << '\n';
        }
    
        {
            typedef GetBetterType<float, short>::type type;
    
            std::cout << std::boolalpha << std::numeric_limits<type>::is_exact << '\n';
            std::cout << std::numeric_limits<type>::digits << '\n';
        }
    
        {
            typedef GetBetterType<short, float>::type type;
    
            std::cout << std::boolalpha << std::numeric_limits<type>::is_exact << '\n';
            std::cout << std::numeric_limits<type>::digits << '\n';
        }
    
        {
            typedef GetBetterType<short, double>::type type;
    
            std::cout << std::boolalpha << std::numeric_limits<type>::is_exact << '\n';
            std::cout << std::numeric_limits<type>::digits << '\n';
        }
    }
    

    Die Namensgebung ist auch noch scheisse... 🤡

    Edit: Peinliche Dummheit beseitigt (ist unten dokumentiert).



  • Tachyon schrieb:

    #define XOR(A,B) (((A) || (B)) && (!((A) && (B))))
    
    ...
    
    enum{value = (!XOR(A,B))
    

    Für Exclusivoder haben wir schon Operatoren:
    bitweise: ^
    boolsch: ^ oder auch !=

    Statt
    !(((A) || (B)) && (!((A) && (B))))
    hättest Du auch schreiben können
    (!A == !B)
    was wegen dem ! sogar dasselbe Ergenis liefert, wenn A und B noch nicht bool sind (beispielsweise A=2, B=3). A==B hätte sonst auch schon gereicht.

    Die Lösung über numeric_limits ist eine gute Idee. Darauf bin ich nicht gekommen, als ich soetwas mal brauchte. 🙂

    Da digits bei Ganzzahlen nur die Bits zählt, die nicht für das Vorzeichen draufgehen, sollte der signed/unsigned Fall auch behandelt werden; denn der Typ von signed() + unsigned() ist ja unsigned.

    Die C++0x Variante benutzt hier den ?:-Operator in Verbindung mit decltype. ?: behandelt auch viele andere Fälle wie Zeiger, Referenzen, strings, etc.

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Tachyon schrieb:

    #define XOR(A,B) (((A) || (B)) && (!((A) && (B))))
    
    ...
    
    enum{value = (!XOR(A,B))
    

    Für Exclusivoder haben wir schon Operatoren:
    bitweise: ^
    boolsch: ^ oder auch !=

    Statt
    !(((A) || (B)) && (!((A) && (B))))
    hättest Du auch schreiben können
    (!A == !B)
    was wegen dem ! sogar dasselbe Ergenis liefert, wenn A und B noch nicht bool sind (beispielsweise A=2, B=3). A==B hätte sonst auch schon gereicht.
    ...

    Ach scheisse. Und gerade darauf war ich so stolz. :p (Manchmal tut es echt weh).

    Naja, bis C++0x richtig portabel einsetzbar ist, wird leider noch etwas Zeit ins Land gehen, denke ich...


Log in to reply