Changeset 7401 for code/trunk/src/libraries/util/Convert.h
- Timestamp:
- Sep 11, 2010, 12:34:00 AM (14 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
/code/branches/doc (added) merged: 7290-7292,7296-7300,7302-7304,7306-7312,7315-7318,7323,7325,7327,7331-7332,7334-7335,7345-7347,7352-7353,7356-7357,7361,7363-7367,7371-7375,7388
- Property svn:mergeinfo changed
-
code/trunk/src/libraries/util/Convert.h
r7305 r7401 28 28 */ 29 29 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++. 33 120 */ 34 121 … … 46 133 #include "ImplicitConversion.h" 47 134 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 iostream64 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 from70 '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 to73 make use of ConverterExplicit. We have to do this for the Ogre classes for instance because they74 define stream operators we don't particulary like.75 */76 77 135 namespace orxonox 78 136 { … … 81 139 /////////////////// 82 140 83 // Default template. No conversion available at all.141 /// Default template. No conversion available at all. 84 142 template <class FromType, class ToType> 85 143 struct ConverterFallback … … 93 151 }; 94 152 95 // If all else fails, try a dynamic_cast for pointer types.153 /// If all else fails, try a dynamic_cast for pointer types. 96 154 template <class FromType, class ToType> 97 155 struct ConverterFallback<FromType*, ToType*> … … 109 167 } 110 168 }; 111 112 ////////////113 // upcast //114 ////////////115 namespace detail116 {117 // perform a static cast if ToType is a base of FromType118 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 FromType125 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 otherwise133 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 }139 169 } 140 170 … … 144 174 /////////////////////// 145 175 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 */ 147 181 template <class FromType, class ToType> 148 182 struct ConverterStringStream … … 159 193 ///////////// 160 194 195 /// Extra namespace to avoid exposing the iostream operators in it 161 196 namespace fallbackTemplates 162 197 { 198 /// Fallback operator <<() (delegates to orxonox::ConverterFallback) 163 199 template <class FromType> 164 200 FORCEINLINE bool operator <<(std::ostream& outstream, const FromType& input) … … 175 211 } 176 212 177 // template that evaluates whether we can convert to std::string via ostringstream213 /// Template that evaluates whether we can convert to std::string via ostringstream 178 214 template <class FromType> 179 215 struct ConverterStringStream<FromType, std::string> … … 182 218 { 183 219 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 185 222 std::ostringstream oss; 223 // Note: std::ostream has operator!() to tell whether any error flag was set 186 224 if (oss << input) 187 225 { … … 201 239 namespace fallbackTemplates 202 240 { 241 /// Fallback operator >>() (delegates to orxonox::ConverterFallback) 203 242 template <class ToType> 204 243 FORCEINLINE bool operator >>(std::istream& instream, ToType& output) 205 244 { 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); 208 247 } 209 248 } 210 249 211 // template that evaluates whether we can convert from std::string via ostringstream250 /// Template that evaluates whether we can convert from std::string via istringstream 212 251 template <class ToType> 213 252 struct ConverterStringStream<std::string, ToType> … … 216 255 { 217 256 using namespace fallbackTemplates; 257 // this operator call chooses fallbackTemplates::operator>>() 258 // only if there's no other fitting function 218 259 std::istringstream iss(input); 219 // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function260 // Note: std::istream has operator!() to tell whether any error flag was set 220 261 if (iss >> (*output)) 221 262 { … … 229 270 namespace orxonox 230 271 { 231 232 272 /////////////////// 233 273 // Implicit Cast // 234 274 /////////////////// 235 275 236 // implicit cast not possible, try stringstream conversion next276 /// %Template delegates to ::ConverterStringStream 237 277 template <class FromType, class ToType> 238 278 FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>) … … 241 281 } 242 282 243 // We can cast implicitely283 /// Makes an implicit cast from \a FromType to \a ToType 244 284 template <class FromType, class ToType> 245 285 FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>) … … 254 294 //////////////////////////////// 255 295 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 */ 257 301 template <class FromType, class ToType> 258 302 struct ConverterExplicit … … 261 305 FORCEINLINE static bool convert(ToType* output, const FromType& input) 262 306 { 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 265 308 return convertImplicitely(output, input, Loki::Int2Type<probe>()); 266 309 } … … 275 318 @brief 276 319 Converts any value to any other as long as there exists a conversion. 320 @details 277 321 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 280 327 */ 281 328 template <class FromType, class ToType> … … 291 338 Converts any value to any other as long as there exists a conversion. 292 339 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 296 346 @param fallback 297 347 A default value that gets written to '*output' if there is no conversion. … … 309 359 } 310 360 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 312 362 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) 314 383 { 315 384 ToType output; … … 318 387 } 319 388 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 339 389 //////////////////////////////// 340 390 // Special string conversions // 341 391 //////////////////////////////// 342 392 343 // Delegateconversion from const char* to std::string393 /// Delegates conversion from const char* to std::string 344 394 template <class ToType> 345 395 struct ConverterExplicit<const char*, ToType> … … 351 401 }; 352 402 353 // These conversions would exhibit ambiguous << or >> operators when using stringstream403 /// Conversion would exhibit ambiguous << or >> operators when using iostream 354 404 template <> 355 405 struct ConverterExplicit<char, std::string> … … 361 411 } 362 412 }; 413 /// Conversion would exhibit ambiguous << or >> operators when using iostream 363 414 template <> 364 415 struct ConverterExplicit<unsigned char, std::string> … … 370 421 } 371 422 }; 423 /// Conversion would exhibit ambiguous << or >> operators when using iostream 372 424 template <> 373 425 struct ConverterExplicit<std::string, char> … … 382 434 } 383 435 }; 436 /// Conversion would exhibit ambiguous << or >> operators when using iostream 384 437 template <> 385 438 struct ConverterExplicit<std::string, unsigned char> … … 396 449 397 450 398 // bool to std::string451 /// Conversion from bool to std::string 399 452 template <> 400 453 struct ConverterExplicit<bool, std::string> … … 410 463 }; 411 464 412 // std::string to bool465 /// Conversion from std::string to bool 413 466 template <> 414 467 struct _UtilExport ConverterExplicit<std::string, bool>
Note: See TracChangeset
for help on using the changeset viewer.