Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Sep 11, 2010, 12:34:00 AM (14 years ago)
Author:
landauf
Message:

merged doc branch back to trunk

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/libraries/util/Convert.h

    r7305 r7401  
    2828 */
    2929
    30 /*!
    31     @file
    32     @brief Definition and Implementation of the Convert class.
     30/**
     31    @defgroup Convert Conversion functions
     32    @ingroup Util
     33*/
     34
     35/** Functions that convert values between different types.
     36@file
     37@ingroup Convert
     38@par Usage
     39    There are three ways to use the conversions depending on what you need. <br>
     40    - For simply converting values without having to know whether the conversion
     41      was successful (for instance float --> string), use orxonox::multi_cast
     42      which effectively works exactly like static_cast, etc.
     43      @code
     44        float input = 42.0;
     45        std::string output = multi_cast<std::string>(input);
     46      @endcode
     47    - If you care about whether the conversion was successful,
     48      use orxonox::convertValue.
     49      @code
     50        std::string input("3.4");
     51        float output;
     52        bool success = convertValue(&output, input);
     53      @endcode
     54    - If you care about success and if you can also feed a fallback value,
     55      use orxonox::convertValue.
     56      @code
     57        std::string input("3.4");
     58        float output;
     59        bool success = convertValue(&output, input, 0.0);
     60      @endcode
     61    - If success doesn't matter but you can feed a fallback value,
     62      use orxonox::getConvertedValue.
     63      @code
     64        std::string input("3.4");
     65        float output = getConvertedValue(input, 0.0);
     66      @endcode
     67@details
     68    The back end of these functions are the actual implementations for the
     69    specific conversions, for instance from Ogre::Vector3 to std::string and
     70    vice versa. Some of them also use the iostream operators. <br>
     71    The real deal is evaluating which function is needed for a conversion based
     72    on the input and output type. But there are lots of catches in conjunction
     73    with templates which explains why there are so many functions in this file.
     74    <br> <br>
     75@par Search Order
     76    Finding the right function is governed by priority rules: <br>
     77    -# (Partial) template specialisation of orxonox::ConverterExplicit::convert()
     78    -# An implicit conversion. This includes 'FooBar' to 'int' if FooBar
     79       defines operator int() or float().
     80    -# Global or member operators for iostream when converting from or
     81       to std::string (and FROM const char*)
     82    -# (Partial) template specialisation of orxonox::ConverterFallback::convert()
     83    -# Fallback function that displays "Could not convert value" with type
     84       information obtained from typeid().
     85@par Implementing conversion functions
     86    To do that you probably need to know a thing or two about the types
     87    involved. So, get ready with that. <br>
     88    Usually the best way to do it is specialising of the orxonox::ConverterFallback
     89    template, like this:
     90    @code
     91    template <>
     92    struct _UtilExport ConverterFallback<std::string, MyType>
     93    {
     94        static bool convert(MyType* output, const std::string& input)
     95        {
     96           ...
     97           return success;
     98        }
     99    };
     100    @endcode
     101    This piece of code converts an std::string to MyType and returns whether the
     102    conversion was successful. You can also use partial specialisation.<br>
     103    The advantage with orxonox::ConverterFallback is that it has a low priority
     104    meaning that when there is an implicit conversion or an iostream method, that
     105    comes first and you don't have to deal with it (and the accompanying
     106    function call ambiguity). <br>
     107    However sometimes you would like to explicitely replace such a conversion.
     108    That's where orxonox::ConverterExplicit comes in handy (for instance we
     109    replaced the operator << conversions for Ogre::VectorX with our own functions).
     110@note
     111    There has to be an exact type match when using template specialisations. <br>
     112    Template specialisations can be defined after including this file.
     113    But any implicit cast function or iostream operator has to be included
     114    in this file!
     115@par Understanding the Code
     116    In order to understand how the templates work, it is probably best to study
     117    the functions in order of calling. There are lots of comments explaining
     118    what happens, but you'll need to understand a deal about partial template
     119    specialisation and function headers are matched in C++.
    33120*/
    34121
     
    46133#include "ImplicitConversion.h"
    47134
    48 ////////////////////////////////////
    49 //// ACTUAL CONVERSION SEQUENCE ////
    50 ////////////////////////////////////
    51 /*
    52     There is a distinct priority when choosing the right conversion function:
    53     Overwrite:
    54     1. (Partial) template specialisation of ConverterExplicit::convert()
    55     Fallbacks:
    56     2. Any possible implicit conversion. This includes 'FooBar' --> 'int' if FooBar defines operator float().
    57     3. Global or member operators for stringstream when converting from or to std::string (or FROM const char*)
    58     4. (Partial) template specialisation of ConverterFallback::convert()
    59     5. Function that simply displays "Could not convert value" with type information obtained from typeid().
    60 
    61     Notes:
    62     There has to be an exact type match when using template specialisations.
    63     Template specialisations can be defined after including this file. Any implicit cast function or iostream
    64     operator has to be declared BEFORE this file gets parsed.
    65 
    66     Defining your own functions:
    67     There are obviously 4 ways to specify a user defined conversion. What should you use?
    68 
    69     Usually, ConverterFallback fits quite well. You won't have to deal with the conversion from
    70     'MyClass' to 'MyClass' by using another explicit template specialisation to avoid ambiguities.
    71 
    72     However if you want to overwrite an implicit conversion or an iostream operator, you really need to
    73     make use of ConverterExplicit. We have to do this for the Ogre classes for instance because they
    74     define stream operators we don't particulary like.
    75 */
    76 
    77135namespace orxonox
    78136{
     
    81139    ///////////////////
    82140
    83     // Default template. No conversion available at all.
     141    /// Default template. No conversion available at all.
    84142    template <class FromType, class ToType>
    85143    struct ConverterFallback
     
    93151    };
    94152
    95     // If all else fails, try a dynamic_cast for pointer types.
     153    /// If all else fails, try a dynamic_cast for pointer types.
    96154    template <class FromType, class ToType>
    97155    struct ConverterFallback<FromType*, ToType*>
     
    109167        }
    110168    };
    111 
    112     ////////////
    113     // upcast //
    114     ////////////
    115     namespace detail
    116     {
    117         // perform a static cast if ToType is a base of FromType
    118         template<class ToType, class FromType>
    119         FORCEINLINE ToType upcast(FromType input, Loki::Int2Type<true>)
    120         {
    121             return static_cast<ToType>(input);
    122         }
    123 
    124         // return zero if ToType is not a base of FromType
    125         template<class ToType, class FromType>
    126         FORCEINLINE ToType upcast(FromType input, Loki::Int2Type<false>)
    127         {
    128             return 0;
    129         }
    130     }
    131 
    132     // performs an upcast if ToType is a base of FromType, returns zero otherwise
    133     template <class ToType, class FromType>
    134     FORCEINLINE ToType upcast(FromType input)
    135     {
    136         enum { probe = ImplicitConversion<FromType, ToType>::exists };
    137         return detail::upcast<ToType, FromType>(input, Loki::Int2Type<probe>());
    138     }
    139169}
    140170
     
    144174///////////////////////
    145175
    146 // Default template for stringstream
     176/** Fallback template for stringstream
     177@details
     178    Neither FromType nor ToType was std::string, therefore
     179    delegate to orxonox::ConverterFallback
     180*/
    147181template <class FromType, class ToType>
    148182struct ConverterStringStream
     
    159193/////////////
    160194
     195/// Extra namespace to avoid exposing the iostream operators in it
    161196namespace fallbackTemplates
    162197{
     198    /// Fallback operator <<() (delegates to orxonox::ConverterFallback)
    163199    template <class FromType>
    164200    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
     
    175211}
    176212
    177 // template that evaluates whether we can convert to std::string via ostringstream
     213/// Template that evaluates whether we can convert to std::string via ostringstream
    178214template <class FromType>
    179215struct ConverterStringStream<FromType, std::string>
     
    182218    {
    183219        using namespace fallbackTemplates;
    184         // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
     220        // this operator call only chooses fallbackTemplates::operator<<()
     221        // if there's no other fitting function
    185222        std::ostringstream oss;
     223        // Note: std::ostream has operator!() to tell whether any error flag was set
    186224        if (oss << input)
    187225        {
     
    201239namespace fallbackTemplates
    202240{
     241    /// Fallback operator >>() (delegates to orxonox::ConverterFallback)
    203242    template <class ToType>
    204243    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
    205244    {
    206         return orxonox::ConverterFallback<std::string, ToType>
    207             ::convert(&output, static_cast<std::istringstream&>(instream).str());
     245        std::string input(static_cast<std::istringstream&>(instream).str());
     246        return orxonox::ConverterFallback<std::string, ToType>::convert(&output, input);
    208247    }
    209248}
    210249
    211 // template that evaluates whether we can convert from std::string via ostringstream
     250/// Template that evaluates whether we can convert from std::string via istringstream
    212251template <class ToType>
    213252struct ConverterStringStream<std::string, ToType>
     
    216255    {
    217256        using namespace fallbackTemplates;
     257        // this operator call chooses fallbackTemplates::operator>>()
     258        // only if there's no other fitting function
    218259        std::istringstream iss(input);
    219         // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
     260        // Note: std::istream has operator!() to tell whether any error flag was set
    220261        if (iss >> (*output))
    221262        {
     
    229270namespace orxonox
    230271{
    231 
    232272    ///////////////////
    233273    // Implicit Cast //
    234274    ///////////////////
    235275
    236     // implicit cast not possible, try stringstream conversion next
     276    /// %Template delegates to ::ConverterStringStream
    237277    template <class FromType, class ToType>
    238278    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
     
    241281    }
    242282
    243     // We can cast implicitely
     283    /// Makes an implicit cast from \a FromType to \a ToType
    244284    template <class FromType, class ToType>
    245285    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
     
    254294    ////////////////////////////////
    255295
    256     // Default template if no specialisation is available
     296    /** Default template if no orxonox::ConverterExplicit is available
     297    @details
     298        Evaluates whether \a FromType can be implicitly converted to \a ToType
     299        by the use the ImplicitConversion magic.
     300    */
    257301    template <class FromType, class ToType>
    258302    struct ConverterExplicit
     
    261305        FORCEINLINE static bool convert(ToType* output, const FromType& input)
    262306        {
    263             // Try implict cast and probe first. If a simple cast is not possible, it will not compile
    264             // We therefore have to out source it into another template function
     307            // Use the probe's value to delegate to the right function
    265308            return convertImplicitely(output, input, Loki::Int2Type<probe>());
    266309        }
     
    275318    @brief
    276319        Converts any value to any other as long as there exists a conversion.
     320    @details
    277321        Otherwise, the conversion will generate a runtime warning and return false.
    278         For information about the different conversion methods (user defined too), see the section
    279         'Actual conversion sequence' in this file above.
     322    @see Convert.h
     323    @param output
     324        A pointer to the variable where the converted value will be stored
     325    @param input
     326        The original value
    280327    */
    281328    template <class FromType, class ToType>
     
    291338        Converts any value to any other as long as there exists a conversion.
    292339        Otherwise, the conversion will generate a runtime warning and return false.
    293         For information about the different conversion methods (user defined too), see the section
    294         'Actual conversion sequence' in this file above.
    295         If the conversion doesn't succeed, 'fallback' is written to '*output'.
     340        If the conversion doesn't succeed, \a fallback is written to \a output.
     341    @see Convert.h
     342    @param output
     343        A pointer to the variable where the converted value will be stored
     344    @param input
     345        The original value
    296346    @param fallback
    297347        A default value that gets written to '*output' if there is no conversion.
     
    309359    }
    310360
    311     // Directly returns the converted value, even if the conversion was not successful.
     361    /// Directly returns the converted value, but uses the fallback on failure. @see convertValue
    312362    template<class FromType, class ToType>
    313     FORCEINLINE ToType getConvertedValue(const FromType& input)
     363    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
     364    {
     365        ToType output;
     366        convertValue(&output, input, fallback);
     367        return output;
     368    }
     369
     370    /**
     371    @brief
     372        Converts any value to any other as long as there exists a conversion.
     373    @details
     374        Use exactly the way you use static_cast, etc. <br>
     375        A failed conversion will return a default instance of \a ToType
     376        (possibly uninitialised)
     377    @see Convert.h
     378    @param input
     379        The original value
     380    */
     381    template<class ToType, class FromType>
     382    FORCEINLINE ToType multi_cast(const FromType& input)
    314383    {
    315384        ToType output;
     
    318387    }
    319388
    320     // Directly returns the converted value, but uses the fallback on failure.
    321     template<class FromType, class ToType>
    322     FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
    323     {
    324         ToType output;
    325         convertValue(&output, input, fallback);
    326         return output;
    327     }
    328 
    329     // Like getConvertedValue, but the template argument order is in reverse.
    330     // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
    331     template<class ToType, class FromType>
    332     FORCEINLINE ToType multi_cast(const FromType& input)
    333     {
    334         ToType output;
    335         convertValue(&output, input);
    336         return output;
    337     }
    338 
    339389    ////////////////////////////////
    340390    // Special string conversions //
    341391    ////////////////////////////////
    342392
    343     // Delegate conversion from const char* to std::string
     393    /// Delegates conversion from const char* to std::string
    344394    template <class ToType>
    345395    struct ConverterExplicit<const char*, ToType>
     
    351401    };
    352402
    353     // These conversions would exhibit ambiguous << or >> operators when using stringstream
     403    /// Conversion would exhibit ambiguous << or >> operators when using iostream
    354404    template <>
    355405    struct ConverterExplicit<char, std::string>
     
    361411        }
    362412    };
     413    /// Conversion would exhibit ambiguous << or >> operators when using iostream
    363414    template <>
    364415    struct ConverterExplicit<unsigned char, std::string>
     
    370421        }
    371422    };
     423    /// Conversion would exhibit ambiguous << or >> operators when using iostream
    372424    template <>
    373425    struct ConverterExplicit<std::string, char>
     
    382434        }
    383435    };
     436    /// Conversion would exhibit ambiguous << or >> operators when using iostream
    384437    template <>
    385438    struct ConverterExplicit<std::string, unsigned char>
     
    396449
    397450
    398     // bool to std::string
     451    /// Conversion from bool to std::string
    399452    template <>
    400453    struct ConverterExplicit<bool, std::string>
     
    410463    };
    411464
    412     // std::string to bool
     465    /// Conversion from std::string to bool
    413466    template <>
    414467    struct _UtilExport ConverterExplicit<std::string, bool>
Note: See TracChangeset for help on using the changeset viewer.