Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Sep 6, 2010, 2:30:12 PM (14 years ago)
Author:
rgrieder
Message:

Elaborated documentation for util/Convert.

File:
1 edited

Legend:

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

    r7297 r7364  
    2828 */
    2929
    30 /*!
    31     @file
    32     @brief Definition and Implementation of the Convert class.
     30/** Functions that convert values between different types.
     31@file
     32@par Usage
     33    There are three ways to use the conversions depending on what you need. <br>
     34    - For simply converting values without having to know whether the conversion
     35      was successful (for instance float --> string), use orxonox::multi_cast
     36      which effectively works exactly like static_cast, etc.
     37      @code
     38        float input = 42.0;
     39        std::string output = multi_cast<std::string>(input);
     40      @endcode
     41    - If you care about whether the conversion was successful,
     42      use orxonox::convertValue.
     43      @code
     44        std::string input("3.4");
     45        float output;
     46        bool success = convertValue(&output, input);
     47      @endcode
     48    - If you care about success and if you can also feed a fallback value,
     49      use orxonox::convertValue.
     50      @code
     51        std::string input("3.4");
     52        float output;
     53        bool success = convertValue(&output, input, 0.0);
     54      @endcode
     55    - If success doesn't matter but you can feed a fallback value,
     56      use orxonox::getConvertedValue.
     57      @code
     58        std::string input("3.4");
     59        float output = getConvertedValue(input, 0.0);
     60      @endcode
     61@details
     62    The back end of these functions are the actual implementations for the
     63    specific conversions, for instance from Ogre::Vector3 to std::string and
     64    vice versa. Some of them also use the iostream operators. <br>
     65    The real deal is evaluating which function is needed for a conversion based
     66    on the input and output type. But there are lots of catches in conjunction
     67    with templates which explains why there are so many functions in this file.
     68    <br> <br>
     69@par Search Order
     70    Finding the right function is governed by priority rules: <br>
     71    -# (Partial) template specialisation of orxonox::ConverterExplicit::convert()
     72    -# An implicit conversion. This includes 'FooBar' to 'int' if FooBar
     73       defines operator int() or float().
     74    -# Global or member operators for iostream when converting from or
     75       to std::string (and FROM const char*)
     76    -# (Partial) template specialisation of orxonox::ConverterFallback::convert()
     77    -# Fallback function that displays "Could not convert value" with type
     78       information obtained from typeid().
     79@par Implementing conversion functions
     80    To do that you probably need to know a thing or two about the types
     81    involved. So, get ready with that. <br>
     82    Usually the best way to do it is specialising of the orxonox::ConverterFallback
     83    template, like this:
     84    @code
     85    template <>
     86    struct _UtilExport ConverterFallback<std::string, MyType>
     87    {
     88        static bool convert(MyType* output, const std::string& input)
     89        {
     90           ...
     91           return success;
     92        }
     93    };
     94    @endcode
     95    This piece of code converts an std::string to MyType and returns whether the
     96    conversion was successful. You can also use partial specialisation.<br>
     97    The advantage with orxonox::ConverterFallback is that it has a low priority
     98    meaning that when there is an implicit conversion or an iostream method, that
     99    comes first and you don't have to deal with it (and the accompanying
     100    function call ambiguity). <br>
     101    However sometimes you would like to explicitely replace such a conversion.
     102    That's where orxonox::ConverterExplicit comes in handy (for instance we
     103    replaced the operator << conversions for Ogre::VectorX with our own functions).
     104@note
     105    There has to be an exact type match when using template specialisations. <br>
     106    Template specialisations can be defined after including this file.
     107    But any implicit cast function or iostream operator has to be included
     108    in this file!
     109@par Understanding the Code
     110    In order to understand how the templates work, it is probably best to study
     111    the functions in order of calling. There are lots of comments explaining
     112    what happens, but you'll need to understand a deal about partial template
     113    specialisation and function headers are matched in C++.
    33114*/
    34115
     
    46127#include "TemplateUtils.h"
    47128
    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 
    77129namespace orxonox
    78130{
     
    81133    ///////////////////
    82134
    83     // Default template. No conversion available at all.
     135    /// Default template. No conversion available at all.
    84136    template <class FromType, class ToType>
    85137    struct ConverterFallback
     
    93145    };
    94146
    95     // If all else fails, try a dynamic_cast for pointer types.
     147    /// If all else fails, try a dynamic_cast for pointer types.
    96148    template <class FromType, class ToType>
    97149    struct ConverterFallback<FromType*, ToType*>
     
    144196///////////////////////
    145197
    146 // Default template for stringstream
     198/** Fallback template for stringstream
     199@details
     200    Neither FromType nor ToType was std::string, therefore
     201    delegate to orxonox::ConverterFallback
     202*/
    147203template <class FromType, class ToType>
    148204struct ConverterStringStream
     
    159215/////////////
    160216
     217/// Extra namespace to avoid exposing the iostream operators in it
    161218namespace fallbackTemplates
    162219{
     220    /// Fallback operator <<() (delegates to orxonox::ConverterFallback)
    163221    template <class FromType>
    164222    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
     
    175233}
    176234
    177 // template that evaluates whether we can convert to std::string via ostringstream
     235/// Template that evaluates whether we can convert to std::string via ostringstream
    178236template <class FromType>
    179237struct ConverterStringStream<FromType, std::string>
     
    182240    {
    183241        using namespace fallbackTemplates;
    184         // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
     242        // this operator call only chooses fallbackTemplates::operator<<()
     243        // if there's no other fitting function
    185244        std::ostringstream oss;
     245        // Note: std::ostream has operator!() to tell whether any error flag was set
    186246        if (oss << input)
    187247        {
     
    201261namespace fallbackTemplates
    202262{
     263    /// Fallback operator >>() (delegates to orxonox::ConverterFallback)
    203264    template <class ToType>
    204265    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
    205266    {
    206         return orxonox::ConverterFallback<std::string, ToType>
    207             ::convert(&output, static_cast<std::istringstream&>(instream).str());
     267        std::string input(static_cast<std::istringstream&>(instream).str());
     268        return orxonox::ConverterFallback<std::string, ToType>::convert(&output, input);
    208269    }
    209270}
    210271
    211 // template that evaluates whether we can convert from std::string via ostringstream
     272/// Template that evaluates whether we can convert from std::string via istringstream
    212273template <class ToType>
    213274struct ConverterStringStream<std::string, ToType>
     
    216277    {
    217278        using namespace fallbackTemplates;
     279        // this operator call chooses fallbackTemplates::operator>>()
     280        // only if there's no other fitting function
    218281        std::istringstream iss(input);
    219         // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
     282        // Note: std::istream has operator!() to tell whether any error flag was set
    220283        if (iss >> (*output))
    221284        {
     
    229292namespace orxonox
    230293{
    231 
    232294    ///////////////////
    233295    // Implicit Cast //
    234296    ///////////////////
    235297
    236     // implicit cast not possible, try stringstream conversion next
     298    /// %Template delegates to ::ConverterStringStream
    237299    template <class FromType, class ToType>
    238300    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
     
    241303    }
    242304
    243     // We can cast implicitely
     305    /// Makes an implicit cast from \a FromType to \a ToType
    244306    template <class FromType, class ToType>
    245307    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
     
    254316    ////////////////////////////////
    255317
    256     // Default template if no specialisation is available
     318    /** Default template if no orxonox::ConverterExplicit is available
     319    @details
     320        Evaluates whether \a FromType can be implicitly converted to \a ToType
     321        by the use the ImplicitConversion magic.
     322    */
    257323    template <class FromType, class ToType>
    258324    struct ConverterExplicit
     
    261327        FORCEINLINE static bool convert(ToType* output, const FromType& input)
    262328        {
    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
     329            // Use the probe's value to delegate to the right function
    265330            return convertImplicitely(output, input, Loki::Int2Type<probe>());
    266331        }
     
    275340    @brief
    276341        Converts any value to any other as long as there exists a conversion.
     342    @details
    277343        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.
     344    @see Convert.h
    280345    @param output
    281346        A pointer to the variable where the converted value will be stored
     
    295360        Converts any value to any other as long as there exists a conversion.
    296361        Otherwise, the conversion will generate a runtime warning and return false.
    297         For information about the different conversion methods (user defined too), see the section
    298         'Actual conversion sequence' in this file above.
    299         If the conversion doesn't succeed, 'fallback' is written to '*output'.
     362        If the conversion doesn't succeed, \a fallback is written to \a output.
     363    @see Convert.h
    300364    @param output
    301365        A pointer to the variable where the converted value will be stored
     
    317381    }
    318382
    319     // Directly returns the converted value, even if the conversion was not successful.
    320383    template<class FromType, class ToType>
    321384    FORCEINLINE ToType getConvertedValue(const FromType& input)
     
    326389    }
    327390
    328     // Directly returns the converted value, but uses the fallback on failure.
     391    /// Directly returns the converted value, but uses the fallback on failure. @see convertValue
    329392    template<class FromType, class ToType>
    330393    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
     
    335398    }
    336399
    337     // Like getConvertedValue, but the template argument order is in reverse.
    338     // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
     400    /**
     401    @brief
     402        Converts any value to any other as long as there exists a conversion.
     403    @details
     404        Use exactly the way you use static_cast, etc. <br>
     405        A failed conversion will return a default instance of \a ToType
     406        (possibly uninitialised)
     407    @see Convert.h
     408    @param input
     409        The original value
     410    */
    339411    template<class ToType, class FromType>
    340412    FORCEINLINE ToType multi_cast(const FromType& input)
     
    349421    ////////////////////////////////
    350422
    351     // Delegate conversion from const char* to std::string
     423    /// Delegates conversion from const char* to std::string
    352424    template <class ToType>
    353425    struct ConverterExplicit<const char*, ToType>
     
    359431    };
    360432
    361     // These conversions would exhibit ambiguous << or >> operators when using stringstream
     433    /// Conversion would exhibit ambiguous << or >> operators when using iostream
    362434    template <>
    363435    struct ConverterExplicit<char, std::string>
     
    369441        }
    370442    };
     443    /// Conversion would exhibit ambiguous << or >> operators when using iostream
     444    template <>
    371445    template <>
    372446    struct ConverterExplicit<unsigned char, std::string>
     
    378452        }
    379453    };
     454    /// Conversion would exhibit ambiguous << or >> operators when using iostream
     455    template <>
    380456    template <>
    381457    struct ConverterExplicit<std::string, char>
     
    390466        }
    391467    };
     468    /// Conversion would exhibit ambiguous << or >> operators when using iostream
    392469    template <>
    393470    struct ConverterExplicit<std::string, unsigned char>
     
    404481
    405482
    406     // bool to std::string
     483    /// Conversion from bool to std::string
    407484    template <>
    408485    struct ConverterExplicit<bool, std::string>
     
    418495    };
    419496
    420     // std::string to bool
     497    /// Conversion from std::string to bool
    421498    template <>
    422499    struct _UtilExport ConverterExplicit<std::string, bool>
Note: See TracChangeset for help on using the changeset viewer.