[Orxonox-commit 2659] r7364 - code/branches/doc/src/libraries/util

rgrieder at orxonox.net rgrieder at orxonox.net
Mon Sep 6 14:30:12 CEST 2010


Author: rgrieder
Date: 2010-09-06 14:30:12 +0200 (Mon, 06 Sep 2010)
New Revision: 7364

Modified:
   code/branches/doc/src/libraries/util/Convert.cc
   code/branches/doc/src/libraries/util/Convert.h
Log:
Elaborated documentation for util/Convert.

Modified: code/branches/doc/src/libraries/util/Convert.cc
===================================================================
--- code/branches/doc/src/libraries/util/Convert.cc	2010-09-06 00:15:49 UTC (rev 7363)
+++ code/branches/doc/src/libraries/util/Convert.cc	2010-09-06 12:30:12 UTC (rev 7364)
@@ -31,7 +31,6 @@
 
 namespace orxonox
 {
-    //template <class FromType, class ToType>
     bool ConverterExplicit<std::string, bool>::convert(bool* output, const std::string& input)
     {
         const std::string& stripped = getLowercase(removeTrailingWhitespaces(input));

Modified: code/branches/doc/src/libraries/util/Convert.h
===================================================================
--- code/branches/doc/src/libraries/util/Convert.h	2010-09-06 00:15:49 UTC (rev 7363)
+++ code/branches/doc/src/libraries/util/Convert.h	2010-09-06 12:30:12 UTC (rev 7364)
@@ -27,9 +27,90 @@
  *      ...
  */
 
-/*!
-    @file
-    @brief Definition and Implementation of the Convert class.
+/** Functions that convert values between different types.
+ at file
+ at par Usage
+    There are three ways to use the conversions depending on what you need. <br>
+    - For simply converting values without having to know whether the conversion
+      was successful (for instance float --> string), use orxonox::multi_cast
+      which effectively works exactly like static_cast, etc.
+      @code
+        float input = 42.0;
+        std::string output = multi_cast<std::string>(input);
+      @endcode
+    - If you care about whether the conversion was successful,
+      use orxonox::convertValue.
+      @code
+        std::string input("3.4");
+        float output;
+        bool success = convertValue(&output, input);
+      @endcode
+    - If you care about success and if you can also feed a fallback value,
+      use orxonox::convertValue.
+      @code
+        std::string input("3.4");
+        float output;
+        bool success = convertValue(&output, input, 0.0);
+      @endcode
+    - If success doesn't matter but you can feed a fallback value,
+      use orxonox::getConvertedValue.
+      @code
+        std::string input("3.4");
+        float output = getConvertedValue(input, 0.0);
+      @endcode
+ at details
+    The back end of these functions are the actual implementations for the
+    specific conversions, for instance from Ogre::Vector3 to std::string and
+    vice versa. Some of them also use the iostream operators. <br>
+    The real deal is evaluating which function is needed for a conversion based
+    on the input and output type. But there are lots of catches in conjunction
+    with templates which explains why there are so many functions in this file.
+    <br> <br>
+ at par Search Order
+    Finding the right function is governed by priority rules: <br>
+    -# (Partial) template specialisation of orxonox::ConverterExplicit::convert()
+    -# An implicit conversion. This includes 'FooBar' to 'int' if FooBar
+       defines operator int() or float().
+    -# Global or member operators for iostream when converting from or
+       to std::string (and FROM const char*)
+    -# (Partial) template specialisation of orxonox::ConverterFallback::convert()
+    -# Fallback function that displays "Could not convert value" with type
+       information obtained from typeid().
+ at par Implementing conversion functions
+    To do that you probably need to know a thing or two about the types
+    involved. So, get ready with that. <br>
+    Usually the best way to do it is specialising of the orxonox::ConverterFallback
+    template, like this:
+    @code
+    template <>
+    struct _UtilExport ConverterFallback<std::string, MyType>
+    {
+        static bool convert(MyType* output, const std::string& input)
+        {
+           ...
+           return success;
+        }
+    };
+    @endcode
+    This piece of code converts an std::string to MyType and returns whether the
+    conversion was successful. You can also use partial specialisation.<br>
+    The advantage with orxonox::ConverterFallback is that it has a low priority
+    meaning that when there is an implicit conversion or an iostream method, that
+    comes first and you don't have to deal with it (and the accompanying
+    function call ambiguity). <br>
+    However sometimes you would like to explicitely replace such a conversion.
+    That's where orxonox::ConverterExplicit comes in handy (for instance we
+    replaced the operator << conversions for Ogre::VectorX with our own functions).
+ at note
+    There has to be an exact type match when using template specialisations. <br>
+    Template specialisations can be defined after including this file.
+    But any implicit cast function or iostream operator has to be included
+    in this file!
+ at par Understanding the Code
+    In order to understand how the templates work, it is probably best to study
+    the functions in order of calling. There are lots of comments explaining
+    what happens, but you'll need to understand a deal about partial template
+    specialisation and function headers are matched in C++.
 */
 
 #ifndef _Converter_H__
@@ -45,42 +126,13 @@
 #include "Debug.h"
 #include "TemplateUtils.h"
 
-////////////////////////////////////
-//// ACTUAL CONVERSION SEQUENCE ////
-////////////////////////////////////
-/*
-    There is a distinct priority when choosing the right conversion function:
-    Overwrite:
-    1. (Partial) template specialisation of ConverterExplicit::convert()
-    Fallbacks:
-    2. Any possible implicit conversion. This includes 'FooBar' --> 'int' if FooBar defines operator float().
-    3. Global or member operators for stringstream when converting from or to std::string (or FROM const char*)
-    4. (Partial) template specialisation of ConverterFallback::convert()
-    5. Function that simply displays "Could not convert value" with type information obtained from typeid().
-
-    Notes:
-    There has to be an exact type match when using template specialisations.
-    Template specialisations can be defined after including this file. Any implicit cast function or iostream
-    operator has to be declared BEFORE this file gets parsed.
-
-    Defining your own functions:
-    There are obviously 4 ways to specify a user defined conversion. What should you use?
-
-    Usually, ConverterFallback fits quite well. You won't have to deal with the conversion from
-    'MyClass' to 'MyClass' by using another explicit template specialisation to avoid ambiguities.
-
-    However if you want to overwrite an implicit conversion or an iostream operator, you really need to
-    make use of ConverterExplicit. We have to do this for the Ogre classes for instance because they
-    define stream operators we don't particulary like.
-*/
-
 namespace orxonox
 {
     ///////////////////
     // No Conversion //
     ///////////////////
 
-    // Default template. No conversion available at all.
+    /// Default template. No conversion available at all.
     template <class FromType, class ToType>
     struct ConverterFallback
     {
@@ -92,7 +144,7 @@
         }
     };
 
-    // If all else fails, try a dynamic_cast for pointer types.
+    /// If all else fails, try a dynamic_cast for pointer types.
     template <class FromType, class ToType>
     struct ConverterFallback<FromType*, ToType*>
     {
@@ -143,7 +195,11 @@
 // ConverterFallback //
 ///////////////////////
 
-// Default template for stringstream
+/** Fallback template for stringstream
+ at details
+    Neither FromType nor ToType was std::string, therefore
+    delegate to orxonox::ConverterFallback
+*/
 template <class FromType, class ToType>
 struct ConverterStringStream
 {
@@ -158,8 +214,10 @@
 // OStream //
 /////////////
 
+/// Extra namespace to avoid exposing the iostream operators in it
 namespace fallbackTemplates
 {
+    /// Fallback operator <<() (delegates to orxonox::ConverterFallback)
     template <class FromType>
     FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
     {
@@ -174,15 +232,17 @@
     }
 }
 
-// template that evaluates whether we can convert to std::string via ostringstream
+/// Template that evaluates whether we can convert to std::string via ostringstream
 template <class FromType>
 struct ConverterStringStream<FromType, std::string>
 {
     FORCEINLINE static bool convert(std::string* output, const FromType& input)
     {
         using namespace fallbackTemplates;
-        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
+        // this operator call only chooses fallbackTemplates::operator<<()
+        // if there's no other fitting function
         std::ostringstream oss;
+        // Note: std::ostream has operator!() to tell whether any error flag was set
         if (oss << input)
         {
             (*output) = oss.str();
@@ -200,23 +260,26 @@
 
 namespace fallbackTemplates
 {
+    /// Fallback operator >>() (delegates to orxonox::ConverterFallback)
     template <class ToType>
     FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
     {
-        return orxonox::ConverterFallback<std::string, ToType>
-            ::convert(&output, static_cast<std::istringstream&>(instream).str());
+        std::string input(static_cast<std::istringstream&>(instream).str());
+        return orxonox::ConverterFallback<std::string, ToType>::convert(&output, input);
     }
 }
 
-// template that evaluates whether we can convert from std::string via ostringstream
+/// Template that evaluates whether we can convert from std::string via istringstream
 template <class ToType>
 struct ConverterStringStream<std::string, ToType>
 {
     FORCEINLINE static bool convert(ToType* output, const std::string& input)
     {
         using namespace fallbackTemplates;
+        // this operator call chooses fallbackTemplates::operator>>()
+        // only if there's no other fitting function
         std::istringstream iss(input);
-        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
+        // Note: std::istream has operator!() to tell whether any error flag was set
         if (iss >> (*output))
         {
             return true;
@@ -228,19 +291,18 @@
 
 namespace orxonox
 {
-
     ///////////////////
     // Implicit Cast //
     ///////////////////
 
-    // implicit cast not possible, try stringstream conversion next
+    /// %Template delegates to ::ConverterStringStream
     template <class FromType, class ToType>
     FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
     {
         return ConverterStringStream<FromType, ToType>::convert(output, input);
     }
 
-    // We can cast implicitely
+    /// Makes an implicit cast from \a FromType to \a ToType
     template <class FromType, class ToType>
     FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
     {
@@ -253,15 +315,18 @@
     // ConverterExplicit Fallback //
     ////////////////////////////////
 
-    // Default template if no specialisation is available
+    /** Default template if no orxonox::ConverterExplicit is available
+    @details
+        Evaluates whether \a FromType can be implicitly converted to \a ToType
+        by the use the ImplicitConversion magic.
+    */
     template <class FromType, class ToType>
     struct ConverterExplicit
     {
         enum { probe = ImplicitConversion<FromType, ToType>::exists };
         FORCEINLINE static bool convert(ToType* output, const FromType& input)
         {
-            // Try implict cast and probe first. If a simple cast is not possible, it will not compile
-            // We therefore have to out source it into another template function
+            // Use the probe's value to delegate to the right function
             return convertImplicitely(output, input, Loki::Int2Type<probe>());
         }
     };
@@ -274,9 +339,9 @@
     /**
     @brief
         Converts any value to any other as long as there exists a conversion.
+    @details
         Otherwise, the conversion will generate a runtime warning and return false.
-        For information about the different conversion methods (user defined too), see the section
-        'Actual conversion sequence' in this file above.
+    @see Convert.h
     @param output
         A pointer to the variable where the converted value will be stored
     @param input
@@ -294,9 +359,8 @@
     @brief
         Converts any value to any other as long as there exists a conversion.
         Otherwise, the conversion will generate a runtime warning and return false.
-        For information about the different conversion methods (user defined too), see the section
-        'Actual conversion sequence' in this file above.
-        If the conversion doesn't succeed, 'fallback' is written to '*output'.
+        If the conversion doesn't succeed, \a fallback is written to \a output.
+    @see Convert.h
     @param output
         A pointer to the variable where the converted value will be stored
     @param input
@@ -316,7 +380,6 @@
         }
     }
 
-    // Directly returns the converted value, even if the conversion was not successful.
     template<class FromType, class ToType>
     FORCEINLINE ToType getConvertedValue(const FromType& input)
     {
@@ -325,7 +388,7 @@
         return output;
     }
 
-    // Directly returns the converted value, but uses the fallback on failure.
+    /// Directly returns the converted value, but uses the fallback on failure. @see convertValue
     template<class FromType, class ToType>
     FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
     {
@@ -334,8 +397,17 @@
         return output;
     }
 
-    // Like getConvertedValue, but the template argument order is in reverse.
-    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
+    /**
+    @brief
+        Converts any value to any other as long as there exists a conversion.
+    @details
+        Use exactly the way you use static_cast, etc. <br>
+        A failed conversion will return a default instance of \a ToType
+        (possibly uninitialised)
+    @see Convert.h
+    @param input
+        The original value
+    */
     template<class ToType, class FromType>
     FORCEINLINE ToType multi_cast(const FromType& input)
     {
@@ -348,7 +420,7 @@
     // Special string conversions //
     ////////////////////////////////
 
-    // Delegate conversion from const char* to std::string
+    /// Delegates conversion from const char* to std::string
     template <class ToType>
     struct ConverterExplicit<const char*, ToType>
     {
@@ -358,7 +430,7 @@
         }
     };
 
-    // These conversions would exhibit ambiguous << or >> operators when using stringstream
+    /// Conversion would exhibit ambiguous << or >> operators when using iostream
     template <>
     struct ConverterExplicit<char, std::string>
     {
@@ -368,7 +440,9 @@
             return true;
         }
     };
+    /// Conversion would exhibit ambiguous << or >> operators when using iostream
     template <>
+    template <>
     struct ConverterExplicit<unsigned char, std::string>
     {
         FORCEINLINE static bool convert(std::string* output, const unsigned char input)
@@ -377,7 +451,9 @@
             return true;
         }
     };
+    /// Conversion would exhibit ambiguous << or >> operators when using iostream
     template <>
+    template <>
     struct ConverterExplicit<std::string, char>
     {
         FORCEINLINE static bool convert(char* output, const std::string& input)
@@ -389,6 +465,7 @@
             return true;
         }
     };
+    /// Conversion would exhibit ambiguous << or >> operators when using iostream
     template <>
     struct ConverterExplicit<std::string, unsigned char>
     {
@@ -403,7 +480,7 @@
     };
 
 
-    // bool to std::string
+    /// Conversion from bool to std::string
     template <>
     struct ConverterExplicit<bool, std::string>
     {
@@ -417,7 +494,7 @@
         }
     };
 
-    // std::string to bool
+    /// Conversion from std::string to bool
     template <>
     struct _UtilExport ConverterExplicit<std::string, bool>
     {




More information about the Orxonox-commit mailing list