Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 1753


Ignore:
Timestamp:
Sep 9, 2008, 10:18:39 PM (16 years ago)
Author:
rgrieder
Message:

Updated Convert.h comments and structure.
Added conversion_cast<ToType>(FromType value) and conversion_cast<ToType>(FromType value, ToType fallback)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/branches/core3/src/util/Convert.h

    r1746 r1753  
    3939#include <string>
    4040#include <sstream>
    41 #include <istream>
    42 #include <boost/static_assert.hpp>
    4341
    4442#include "Math.h"
    4543#include "Debug.h"
    46 #include "SubString.h"
     44
     45// Gcc generates warnings when implicitely casting from float to int for instance.
     46// This is however exactly what convertValue does, so we need to suppress the warnings.
     47// They only occur in when using the ImplicitConversion template.
     48#if ORXONOX_COMPILER == ORXONOX_COMPILER_GCC
     49#  pragma GCC system_header
     50#endif
    4751
    4852///////////////////////////////////
     
    5054///////////////////////////////////
    5155
    52 // These conversions exhibit ambiguous << or >> operators when using stringstream
    53 inline bool explicitConversion(std::string* output, const char input)
    54 {
    55     *output = std::string(input, 1);
    56     return true;
    57 }
    58 inline bool explicitConversion(std::string* output, const unsigned char input)
    59 {
    60     *output = std::string(input, 1);
    61     return true;
    62 }
    63 inline bool explicitConversion(char* output, const std::string input)
    64 {
    65     if (input != "")
    66         *output = input[0];
    67     else
    68         *output = '\0';
    69     return true;
    70 }
    71 inline bool explicitConversion(unsigned char* output, const std::string input)
    72 {
    73     if (input != "")
    74         *output = input[0];
    75     else
    76         *output = '\0';
    77     return true;
    78 }
    79 
    80 ///////////////////////////
    81 // Static type detection //
    82 ///////////////////////////
     56
     57///////////////////////////////////////////////
     58// Static detection for conversion functions //
     59///////////////////////////////////////////////
    8360
    8461/* The idea to use the sizeof() operator on return functions to determine function existance
    8562   is described in 'Moder C++ design' by Alexandrescu (2001). */
    8663
    87 //template <int a, int b>
    88 //struct TemplateDebugger
    89 //{
    90 //    static int debug(int c, int d) { return 0; } //BOOST_STATIC_ASSERT(0); }
    91 //};
    92 
    9364namespace conversionTests
    9465{
    95 
    96     // Two struct with very different sizes
    97     struct VerySmallStruct { char dummy[1]; };
    98     struct VeryBigStruct   { char dummy[1024]; }; // Big is surely larger than Small, even with alignments
    99 }
    100 
    101 //namespace generalFunctionTemplate
    102 //{
    103     // Keep this function out of conversion namespaces because the compiler gives a general
    104     // template in the same namesapace a higher priority than any specialisation.
    105     // This function simply accepts anything but has lower priority than specialisations.
    106     // It can be identified by the larger return value.
     66    // A struct that is guaranteed to be larger than any return type of our conversion functions.
     67    // So we simply add all the sizes of the return types plus a little bit more.
     68    struct VeryBigStruct
     69    {
     70        char intSize[sizeof(int)];
     71        char issSize[sizeof(std::istringstream)];
     72        char ossSize[sizeof(std::ostringstream)];
     73        char boolSize[sizeof(bool)];
     74        char addingMore[4096]; // just to be sure ;)
     75    };
     76}
     77
     78namespace separate_namespace
     79{
     80    // We want to keep the templates for the convert functions out of global namespace so that there
     81    // are no ambiguities. These templates are never used anyway, they only serve to detect whether
     82    // there is a global funciton for a specific conversion or not.
     83    // Now why not putting this in namespace 'conversionTests'?
     84    // I can not tell for sure, but I think there is a bug in msvc 8. It chooses this general template
     85    // (if it was in 'conversionTests') over a better fitting function in global namespace.
     86    // The solution is to use another namespace and then apply the 'using' directive in 'conversionTests'.
     87    // Unfortunately there is a (somewhat documented) bug in msvc 8 that exposes namespace members
     88    // globally when applying the 'using' directive in a namespace. And it so happens that the bug is
     89    // triggered in this file. This unwanted global exposure hopefully doesn't cause ambiguities.
    10790    template <class AnyToType, class AnyFromType>
    10891    conversionTests::VeryBigStruct explicitConversion(AnyToType* output, const AnyFromType input)
    10992    {
    110         // The function is exposed globally because of the "using namespace" in conversionTests.
    111         // We have to make sure noboy uses it, so a good compiler error would be nice.
     93        // We have to make sure noboy uses it , so a good compiler error would be nice.
    11294        *output = (AnyToType)input; // Do not use this function!
    113         //BOOST_STATIC_ASSERT(0); // just to be sure
    114                 return *(new conversionTests::VeryBigStruct());
    115     }
    116     //conversionTests::VeryBigStruct explicitConversion(...);
    117 //}
     95        // gcc does some syntax checking anyway. So return a correct value that is not a temporary.
     96            return *(new conversionTests::VeryBigStruct());
     97    }
     98}
    11899
    119100namespace conversionTests
    120101{
    121     //using namespace generalFunctionTemplate; // Why in separate namespace? See above
    122 
    123     // This operators simply accept anything but have lower priority than specialisations.
    124     // It can be identified by the larger return value.
     102    // Part of the msvc hack. See above in the namespace for more explanations.
     103    using namespace separate_namespace;
     104
     105    // These operators simply accept anything but have lower priority than specialisations
     106    // or exact-match non-template functions.
     107    // They can be identified by the larger return value.
     108    // We put these in a seperate namespace to avoid conflicts with ambiguities.
    125109    template <class Any>
    126110    conversionTests::VeryBigStruct operator<<(std::ostream& outstream, const Any anything);
     
    128112    conversionTests::VeryBigStruct operator>>(std::istream& instream,  const Any anything);
    129113
    130     // checks for implicit conversion
    131114    template <class FromType, class ToType>
    132115    class ImplicitConversion
    133116    {
    134117    private:
    135         static VerySmallStruct test(ToType); // only accepts ToType, but is preferred over '...'
    136                 //template <class AnyType>
    137         static VeryBigStruct   test(...);//const AnyType anything);    // accepts anything
     118        ImplicitConversion(); ImplicitConversion(const ImplicitConversion&); ~ImplicitConversion();
     119        // Gets chosen only if there is an implicit conversion from FromType to ToType.
     120        static int test(ToType);
     121        // Accepts any argument. Why do we not use a template? The reason is that with templates,
     122        // the function above is only taken iff it is an exact type match. But since we want to
     123        // check for implicit conversion, we have to use the ellipsis.
     124        static VeryBigStruct   test(...);
    138125        static FromType object; // helper object to handle private c'tor and d'tor
    139126    public:
    140         enum { exists = sizeof(test(object)) == sizeof(VerySmallStruct) };
    141     };
    142 
    143     // checks for explicit conversion with explicitConversion()
    144     template <class FromType, class ToType, int asdf>
     127        // test(object) has only 'VerySmallStruct' return type iff the compiler doesn't choose test(...)
     128        enum { exists = !(sizeof(test(object)) == sizeof(VeryBigStruct)) };
     129    };
     130
     131    template <class FromType, class ToType>
    145132    class ExplicitConversion
    146133    {
    147134    private:
     135        ExplicitConversion(); ExplicitConversion(const ExplicitConversion&); ~ExplicitConversion();
    148136        static FromType objectFromType; // helper object to handle private c'tor and d'tor
    149137        static ToType   objectToType;   // helper object to handle private c'tor and d'tor
    150138    public:
    151         enum { exists = sizeof(explicitConversion(&objectToType, objectFromType)) == sizeof(VerySmallStruct) };
    152         static void test();
    153     };
    154 
    155     //template <int asdf>
    156     //class ExplicitConversion<float, int, asdf>
    157     //{
    158     //private:
    159     //    static float objectFromType; // helper object to handle private c'tor and d'tor
    160     //    static int   objectToType;   // helper object to handle private c'tor and d'tor
    161     //public:
    162     //    enum { exists = sizeof(explicitConversion(&objectToType, objectFromType)) == sizeof(VerySmallStruct) };
    163     //    static void test() { TemplateDebugger<sizeof(explicitConversion(&objectToType, objectFromType)), sizeof(VerySmallStruct)>::debug(1,2); }
    164     //};
    165 
    166     // checks for conversion via istringstream
     139        enum { exists = !(sizeof(explicitConversion(&objectToType, objectFromType)) == sizeof(VeryBigStruct)) };
     140    };
     141
    167142    template <class Type>
    168143    class IStringStreamOperator
    169144    {
     145        IStringStreamOperator(); IStringStreamOperator(const IStringStreamOperator&); ~IStringStreamOperator();
    170146        static std::istringstream istream_; // helper object to perform the '>>' operation
    171147        static Type object;                 // helper object to handle private c'tor and d'tor
    172148    public:
    173         enum { exists = (sizeof(istream_ >> object) < sizeof(VerySmallStruct) + 512) };
    174     };
    175 
    176     // checks for conversion via ostringstream
     149        enum { exists = !(sizeof(istream_ >> object) == sizeof(VeryBigStruct)) };
     150    };
     151
    177152    template <class Type>
    178153    class OStringStreamOperator
    179154    {
     155        OStringStreamOperator(); OStringStreamOperator(const OStringStreamOperator&); ~OStringStreamOperator();
    180156        static std::ostringstream ostream_; // helper object to perform the '<<' operation
    181157        static Type object;                 // helper object to handle private c'tor and d'tor
    182158    public:
    183         enum { exists = (sizeof(ostream_ << object) < sizeof(VerySmallStruct) + 512) };
    184     };
    185 }
    186 
    187 // shortcut without namespace
     159        enum { exists = !(sizeof(ostream_ << object) == sizeof(VeryBigStruct)) };
     160    };
     161}
     162
     163/* Shortcuts because we usually don't have a namespace in util/ but need one here for the conversion tests*/
     164
     165/**
     166@brief
     167    Checks for an implicit conversion FromType --> TyType.
     168    This also works for user defined conversion operators.
     169    Usage: ImplicitConversion<FromType, ToType>::exists
     170*/
    188171template <class FromType, class ToType>
    189172struct ImplicitConversion
    190173{ enum { exists = conversionTests::ImplicitConversion<FromType, ToType>::exists }; };
    191174
    192 // shortcut without namespace
     175/**
     176@brief
     177    Checks for an explicit conversion FromType --> TyType via 'explicConversion()' function.
     178    There has to e an exact type match for a success!
     179    Usage: ExplicitConversion<FromType, ToType>::exists
     180*/
    193181template <class FromType, class ToType>
    194182struct ExplicitConversion
    195 { enum { exists = conversionTests::ExplicitConversion<FromType, ToType, 4>::exists }; };
    196 
    197 // shortcut without namespace
     183{ enum { exists = conversionTests::ExplicitConversion<FromType, ToType>::exists }; };
     184
     185/**
     186@brief
     187    Checks for an explicit conversion std::string --> TyType via >> operator.
     188    There has to e an exact type match for a success!
     189    Usage: IStringStreamConversion<FromType, ToType>::exists
     190*/
    198191template <class Type>
    199192struct IStringStreamOperator
    200193{ enum { exists = conversionTests::IStringStreamOperator<Type>::exists }; };
    201194
    202 // shortcut without namespace
     195/**
     196@brief
     197    Checks for an explicit conversion std::string --> TyType via << operator.
     198    There has to e an exact type match for a success!
     199    Usage: OStringStreamConversion<FromType, ToType>::exists
     200*/
    203201template <class Type>
    204202struct OStringStreamOperator
     
    206204
    207205
    208 ///////////////////////////////
    209 // Conversion Template Stuff //
    210 ///////////////////////////////
    211 
     206
     207////////////////////////////////////
     208//// ACTUAL CONVERSION SEQUENCE ////
     209////////////////////////////////////
     210/*
     211    There is a distinct priority when choosing the right conversion function:
     212    Overwrites:
     213    1. (Partial) template specialisation of ConverterExplicit::convert
     214    2. Global functions explicitConversion(ToType* output, const FromType input)
     215    Fallbacks:
     216    3. Any possible implicit conversion. This includes FooBar --> int if FooBar defines operator float().
     217    4. Global or member operators for stringstream when converting from or to std::string (or FROM const char*)
     218    5. Function that simply displays "Could not convert value" with information obtained from typeid().
     219
     220    A note: There has to be an exact type match (or according to the rules of template spec.) except for 3.
     221
     222    There are obviously a lot of ways to specifiy a user defined conversion. What should I use?
     223    When using any non-template function based conversion (implicit conversion, explicitConversion, << or >>)
     224    then you should consider that this function has to be defined prior to including this file.
     225    If you do not whish do do that, you will have to spcecialsize the ConverterExplicit template.
     226    There is a not so obvious advantage of the other way (non-template): You could declare each conversion function
     227    in the Prereqs file of the corresponding library. Then you can use the conversion everywhere.
     228    This is not possible with template specialisations even when defining them in this file (You would create
     229    a circular dependency when using a class from Core for instance, because complete template specialisations
     230    get compiled anyway (there is no template parameter)).
     231*/
     232
     233// Put everything in a namespace to avoid unnecessary exposure
     234// Note that the textual order of the functions is in reverse.
    212235namespace conversion
    213236{
     
    220243    struct StringStreamPossible { };
    221244
    222     // No Conversion possible, default template
     245
     246    ///////////////////
     247    // No Conversion //
     248    ///////////////////
     249
     250    // Default template, no Conversion possible
    223251    template <class ToType, class FromType, int Dummy>
    224     struct Converter
     252    struct ConverterSS
    225253    {
    226254        static bool convert(ToType* output, FromType input)
    227255        {
    228             // Do not allow impossible conversions
    229             //(*output) = input; // this WILL trigger a compiler error
    230             //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
     256            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
     257                    << " to type " << typeid(ToType).name() << std::endl;
    231258            return false;
    232259        }
    233260    };
    234 }
    235 
    236 
    237 ///////////////////////
    238 //Explicit Conversion//
    239 ///////////////////////
    240 
    241 namespace conversion
    242 {
    243     // We can cast explicitely via function overloading, this overwrites any other possible cast
    244     template <class ToType, class FromType>
    245     inline bool convert(ToType* output, const FromType& input, ExplicitPossible<true>)
    246     {
    247         // This function can by anywhere globally!
    248         //int a = TemplateDebugger<1,2>::debug(1,1);
    249         //conversionTests::ExplicitConversion<FromType, ToType, 4>::test();
    250         //BOOST_STATIC_ASSERT(0);
    251         return explicitConversion(output, input);
    252     }
    253 
    254     // No function explict conversion, try implicit cast
    255     template <class ToType, class FromType>
    256     inline bool convert(ToType* output, const FromType& input, ExplicitPossible<false>)
    257     {
    258         return convert(output, input, ImplicitPossible<ImplicitConversion<FromType, ToType>::exists>());
    259         //return ConverterSpecialised<ToType, FromType>::convert(output, input);
    260     }
    261 }
    262 
    263 // template that is used when no explicit template specialisation is available
    264 template <class ToType, class FromType>
    265 struct ConverterSpecialised
    266 {
    267     static bool convert(ToType* output, const FromType& input)
    268     {
    269         // check for explicit conversion via function overloading
    270         return conversion::convert(output, input,
    271             conversion::ExplicitPossible<ExplicitConversion<FromType, ToType>::exists>());
    272     }
    273 };
    274 
    275 namespace conversion
    276 {
    277     /////////////////
    278     //Implicit Cast//
    279     /////////////////
     261
     262
     263    ///////////////////
     264    // OStringStream //
     265    ///////////////////
     266
     267    // Conversion via ostringstream
     268    template <class FromType>
     269    inline bool convertOStringStream(std::string* output, const FromType& input)
     270    {
     271        std::ostringstream oss;
     272        if (oss << input)
     273        {
     274            (*output) = oss.str();
     275            return true;
     276        }
     277        else
     278            return false;
     279    }
     280
     281    // template that evaluates whether OStringStream is possible for conversions to std::string
     282    template <class FromType, int Dummy>
     283    struct ConverterSS<std::string, FromType, Dummy>
     284    {
     285        // probe for '<<' stringstream operator
     286        static bool convert(std::string* output, const FromType& input)
     287        {
     288            const bool probe = OStringStreamOperator<FromType>::exists;
     289            return convert(output, input, StringStreamPossible<probe>());
     290        }
     291        // Conversion with ostringstream possible
     292        static bool convert(std::string* output, const FromType& input, StringStreamPossible<true>)
     293        {
     294            return convertOStringStream(output, input);
     295        }
     296        // Conversion with ostringstream not possible
     297        static bool convert(std::string* output, const FromType& input, StringStreamPossible<false>)
     298        {
     299            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
     300                    << " to std::string" << std::endl;
     301            return false;
     302        }
     303    };
     304
     305
     306    ///////////////////
     307    // IStringStream //
     308    ///////////////////
     309
     310    // conversion from std::string via istringstream
     311    template <class ToType>
     312    inline bool convertIStringStream(ToType* output, const std::string& input)
     313    {
     314        std::istringstream iss(input);
     315        if (iss >> (*output))
     316        {
     317            return true;
     318        }
     319        else
     320            return false;
     321    }
     322
     323    // template that evaluates whether IStringStream is possible for conversions from std::string
     324    template <class ToType, int Dummy>
     325    struct ConverterSS<ToType, std::string, Dummy>
     326    {
     327        // probe for '>>' stringstream operator
     328        static bool convert(ToType* output, const std::string& input)
     329        {
     330            const bool probe = IStringStreamOperator<ToType>::exists;
     331            return convert(output, input, StringStreamPossible<probe>());
     332        }
     333        // Conversion with istringstream possible
     334        static bool convert(ToType* output, const std::string& input, StringStreamPossible<true>)
     335        {
     336            return convertIStringStream(output, input);
     337        }
     338        // Conversion with istringstream not possible
     339        static bool convert(ToType* output, const std::string& input, StringStreamPossible<false>)
     340        {
     341            COUT(2) << "Could not convert std::string value to type " << typeid(ToType).name() << std::endl;
     342            return false;
     343        }
     344    };
     345
     346
     347    ///////////////////
     348    // Implicit Cast //
     349    ///////////////////
    280350
    281351    // We can cast implicitely
     
    287357    }
    288358
    289     // No implicit cast, leave it up to << and >>
     359    // No implicit cast, leave it up to << and >> via template spcialisation
    290360    template <class ToType, class FromType>
    291361    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<false>)
    292362    {
    293         return Converter<ToType, FromType, 0>::convert(output, input);
    294     }
    295 
    296 
    297     /////////////////
    298     //OStringStream//
    299     /////////////////
    300 
    301     // Conversion via ostringstream
    302     template <class FromType>
    303     bool convertOStringStream(std::string* output, const FromType& input)
    304     {
    305         std::ostringstream oss;
    306         if (oss << input)
    307         {
    308             (*output) = oss.str();
    309             return true;
    310         }
    311         else
    312             return false;
    313     }
    314 
    315     // template that evaluates whether OStringStream is possible
    316     template <class FromType, int Dummy>
    317     struct Converter<std::string, FromType, Dummy>
    318     {
    319         // convert to std::string, probe for '<<' stringstream operator
    320         static bool convert(std::string* output, const FromType& input)
    321         {
    322             return convert(output, input, StringStreamPossible<OStringStreamOperator<FromType>::exists>());
    323             //conversion::OStringStreamOperator<FromType>::test();
    324         }
    325 
    326         // Conversion with ostringstream possible
    327         static bool convert(std::string* output, const FromType& input, StringStreamPossible<true>)
    328         {
    329             return convertOStringStream(output, input);
    330         }
    331 
    332         // Conversion with ostringstream not possible
    333         static bool convert(std::string* output, const FromType& input, StringStreamPossible<false>)
    334         {
    335             // Do not allow impossible conversions
    336             //(*output) = input; // this WILL trigger a compiler error
    337             //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
    338             return false;
    339         }
    340     };
    341 
    342 
    343     /////////////////
    344     //IStringStream//
    345     /////////////////
    346 
    347     // conversion from std::string via istringstream
    348     template <class ToType>
    349     bool convertIStringStream(ToType* output, const std::string& input)
    350     {
    351         std::istringstream iss(input);
    352         if (iss >> (*output))
    353         {
    354             return true;
    355         }
    356         else
    357             return false;
    358     }
    359 
    360     // template that evaluates whether IStringStream is possible
    361     template <class ToType, int Dummy>
    362     struct Converter<ToType, std::string, Dummy>
    363     {
    364         // convert from std::string, probe for '>>' stringstream operator
    365         static bool convert(ToType* output, const std::string& input)
    366         {
    367             return convert(output, input, StringStreamPossible<IStringStreamOperator<ToType>::exists>());
    368         }
    369 
    370         // Conversion with istringstream possible
    371         static bool convert(ToType* output, const std::string& input, StringStreamPossible<true>)
    372         {
    373             return convertIStringStream(output, input);
    374         }
    375 
    376         // Conversion with istringstream not possible
    377         static bool convert(ToType* output, const std::string& input, StringStreamPossible<false>)
    378         {
    379             // Do not allow impossible conversions
    380             //(*output) = input; // this WILL trigger a compiler error
    381             //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
    382             return false;
    383         }
    384     };
    385 
    386 
    387     ///////////////
    388     //const char*//
    389     ///////////////
    390 
    391     // delegate conversion from const char* via string
    392     template <class ToType, int Dummy>
    393     struct Converter<ToType, const char*, Dummy>
    394     {
    395         // convert from const char* via std::string
    396         static bool convert(ToType* output, const char* input)
    397         { return Converter<ToType, std::string, Dummy>::convert(output, input); }
    398     };
    399 }
    400 
    401 
    402 ////////////////////
    403 //Public Functions//
    404 ////////////////////
     363        return ConverterSS<ToType, FromType, 0>::convert(output, input);
     364    }
     365
     366
     367    /////////////////////////
     368    // Explicit Conversion //
     369    /////////////////////////
     370
     371    // We can convert explicitely via function overloading
     372    template <class ToType, class FromType>
     373    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<true>)
     374    {
     375        // This function can by anywhere globally!
     376        return explicitConversion(output, input);
     377    }
     378
     379    // No explict conversion via explicitConversion(), try implicit cast
     380    template <class ToType, class FromType>
     381    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<false>)
     382    {
     383        const bool probe = ImplicitConversion<FromType, ToType>::exists;
     384        return convert(output, input, ImplicitPossible<probe>());
     385    }
     386
     387    // template that is used when no explicit template specialisation is available
     388    // try explicitConversion() function next.
     389    template <class ToType, class FromType>
     390    struct ConverterExplicit
     391    {
     392        static bool convert(ToType* output, const FromType& input)
     393        {
     394            // check for explicit conversion via function overloading
     395            const bool probe = ExplicitConversion<FromType, ToType>::exists;
     396            // why conversion:: ? --> below is a 'using' directive, so this template usually
     397            // gets instantiated in global namespace
     398            return conversion::convert(output, input, ExplicitPossible<probe>());
     399        }
     400    };
     401}
     402
     403
     404//////////////////////
     405// Public Functions //
     406//////////////////////
     407
     408// We usually don't have a namespace in util/ but it would still be desirable to lock
     409// everything internal away in namespace conversion.
     410using conversion::ConverterExplicit;
    405411
    406412/**
     
    408414    Converts any value to any other as long as there exits a conversion.
    409415    Otherwise, the conversion will generate a runtime warning.
     416    For information about the different conversion methods (user defined too), see the section
     417    'Actual conversion sequence' in this file above.
    410418*/
    411419template <class ToType, class FromType>
    412420inline bool convertValue(ToType* output, const FromType& input)
    413421{
    414     // check whether we can convert one type to the other explicitely via function overloading
    415     //conversionTests::ExplicitConversion<FromType, ToType, 4>::test();
    416     return ConverterSpecialised<ToType, FromType>::convert(output, input);
    417     //return conversion::convert(output, input,
    418     //    conversion::ExplicitPossible<ExplicitConversion<FromType, ToType>::exists>());
    419 }
    420 
    421 // Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
     422    // check whether we can convert one type to the other explicitely via explicit template specialisations
     423    return ConverterExplicit<ToType, FromType>::convert(output, input);
     424}
     425
     426// For compatibility reasons. The same, but with capital ConvertValue
    422427template<class FromType, class ToType>
    423 static bool ConvertValue(ToType* output, const FromType& input)
     428inline bool ConvertValue(ToType* output, const FromType& input)
    424429{
    425430    return convertValue(output, input);
    426431}
     432
     433// Calls convertValue and returns true if the conversion was successful.
     434// Otherwise the fallback is used.
    427435template<class FromType, class ToType>
    428 static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback)
     436inline bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback)
    429437{
    430438    if (convertValue(output, input))
     
    435443}
    436444
    437 // Helper function: Calls convertValue with and without default value and returns the converted value
     445// Directly returns the converted value, even if the conversion was not successful.
    438446template<class FromType, class ToType>
    439 static ToType getConvertedValue(const FromType& input)
    440 {
    441     ToType output = ToType();
     447inline ToType getConvertedValue(const FromType& input)
     448{
     449    ToType output;
    442450    ConvertValue(&output, input);
    443451    return output;
    444452}
     453
     454// Directly returns the converted value, but uses the fallback on failure.
    445455template<class FromType, class ToType>
    446 static ToType getConvertedValue(const FromType& input, const ToType& fallback)
     456inline ToType getConvertedValue(const FromType& input, const ToType& fallback)
    447457{
    448458    ToType output = fallback;
     
    451461}
    452462
     463// Like getConvertedValue, but the template argument order is in reverse.
     464// That means you can call it exactly like static_cast<ToType>(fromTypeValue).
     465template<class ToType, class FromType>
     466inline ToType conversion_cast(const FromType& input)
     467{
     468    ToType output;
     469    ConvertValue(&output, input);
     470    return output;
     471}
     472
     473// Like conversion_cast above, but uses a fallback on failure.
     474template<class ToType, class FromType>
     475inline ToType conversion_cast(const FromType& input, const ToType& fallback)
     476{
     477    ToType output = fallback;
     478    ConvertValue(&output, input, fallback);
     479    return output;
     480}
     481
     482
     483///////////////////////////////////////
     484// Explicit Template Specialisations //
     485///////////////////////////////////////
     486
     487// delegate conversion from const char* via std::string
     488template <class ToType>
     489struct ConverterExplicit<ToType, const char*>
     490{
     491    // convert from const char* via std::string
     492    static bool convert(ToType* output, const char* input)
     493    {
     494        return conversion::ConverterSS<ToType, std::string, 0>::convert(output, input);
     495    }
     496};
     497
     498// These conversions would exhibit ambiguous << or >> operators when using stringstream
     499template <> struct ConverterExplicit<std::string, char>
     500{
     501    static bool convert(std::string* output, const char input)
     502    {
     503        *output = std::string(input, 1);
     504        return true;
     505    }
     506};
     507template <> struct ConverterExplicit<std::string, unsigned char>
     508{
     509    static bool convert(std::string* output, const unsigned char input)
     510    {
     511        *output = std::string(input, 1);
     512        return true;
     513    }
     514};
     515template <> struct ConverterExplicit<char, std::string>
     516{
     517    static bool convert(char* output, const std::string input)
     518    {
     519        if (input != "")
     520            *output = input[0];
     521        else
     522            *output = '\0';
     523        return true;
     524    }
     525};
     526template <> struct ConverterExplicit<unsigned char, std::string>
     527{
     528    static bool convert(unsigned char* output, const std::string input)
     529    {
     530        if (input != "")
     531            *output = input[0];
     532        else
     533            *output = '\0';
     534        return true;
     535    }
     536};
     537
    453538#endif /* _Convert_H__ */
Note: See TracChangeset for help on using the changeset viewer.