Changeset 1753
- Timestamp:
- Sep 9, 2008, 10:18:39 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/core3/src/util/Convert.h
r1746 r1753 39 39 #include <string> 40 40 #include <sstream> 41 #include <istream>42 #include <boost/static_assert.hpp>43 41 44 42 #include "Math.h" 45 43 #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 47 51 48 52 /////////////////////////////////// … … 50 54 /////////////////////////////////// 51 55 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 /////////////////////////////////////////////// 83 60 84 61 /* The idea to use the sizeof() operator on return functions to determine function existance 85 62 is described in 'Moder C++ design' by Alexandrescu (2001). */ 86 63 87 //template <int a, int b>88 //struct TemplateDebugger89 //{90 // static int debug(int c, int d) { return 0; } //BOOST_STATIC_ASSERT(0); }91 //};92 93 64 namespace conversionTests 94 65 { 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 78 namespace 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. 107 90 template <class AnyToType, class AnyFromType> 108 91 conversionTests::VeryBigStruct explicitConversion(AnyToType* output, const AnyFromType input) 109 92 { 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. 112 94 *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 } 118 99 119 100 namespace conversionTests 120 101 { 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. 125 109 template <class Any> 126 110 conversionTests::VeryBigStruct operator<<(std::ostream& outstream, const Any anything); … … 128 112 conversionTests::VeryBigStruct operator>>(std::istream& instream, const Any anything); 129 113 130 // checks for implicit conversion131 114 template <class FromType, class ToType> 132 115 class ImplicitConversion 133 116 { 134 117 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(...); 138 125 static FromType object; // helper object to handle private c'tor and d'tor 139 126 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> 145 132 class ExplicitConversion 146 133 { 147 134 private: 135 ExplicitConversion(); ExplicitConversion(const ExplicitConversion&); ~ExplicitConversion(); 148 136 static FromType objectFromType; // helper object to handle private c'tor and d'tor 149 137 static ToType objectToType; // helper object to handle private c'tor and d'tor 150 138 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 167 142 template <class Type> 168 143 class IStringStreamOperator 169 144 { 145 IStringStreamOperator(); IStringStreamOperator(const IStringStreamOperator&); ~IStringStreamOperator(); 170 146 static std::istringstream istream_; // helper object to perform the '>>' operation 171 147 static Type object; // helper object to handle private c'tor and d'tor 172 148 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 177 152 template <class Type> 178 153 class OStringStreamOperator 179 154 { 155 OStringStreamOperator(); OStringStreamOperator(const OStringStreamOperator&); ~OStringStreamOperator(); 180 156 static std::ostringstream ostream_; // helper object to perform the '<<' operation 181 157 static Type object; // helper object to handle private c'tor and d'tor 182 158 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 */ 188 171 template <class FromType, class ToType> 189 172 struct ImplicitConversion 190 173 { enum { exists = conversionTests::ImplicitConversion<FromType, ToType>::exists }; }; 191 174 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 */ 193 181 template <class FromType, class ToType> 194 182 struct 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 */ 198 191 template <class Type> 199 192 struct IStringStreamOperator 200 193 { enum { exists = conversionTests::IStringStreamOperator<Type>::exists }; }; 201 194 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 */ 203 201 template <class Type> 204 202 struct OStringStreamOperator … … 206 204 207 205 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. 212 235 namespace conversion 213 236 { … … 220 243 struct StringStreamPossible { }; 221 244 222 // No Conversion possible, default template 245 246 /////////////////// 247 // No Conversion // 248 /////////////////// 249 250 // Default template, no Conversion possible 223 251 template <class ToType, class FromType, int Dummy> 224 struct Converter 252 struct ConverterSS 225 253 { 226 254 static bool convert(ToType* output, FromType input) 227 255 { 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; 231 258 return false; 232 259 } 233 260 }; 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 /////////////////// 280 350 281 351 // We can cast implicitely … … 287 357 } 288 358 289 // No implicit cast, leave it up to << and >> 359 // No implicit cast, leave it up to << and >> via template spcialisation 290 360 template <class ToType, class FromType> 291 361 inline bool convert(ToType* output, const FromType& input, ImplicitPossible<false>) 292 362 { 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. 410 using conversion::ConverterExplicit; 405 411 406 412 /** … … 408 414 Converts any value to any other as long as there exits a conversion. 409 415 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. 410 418 */ 411 419 template <class ToType, class FromType> 412 420 inline bool convertValue(ToType* output, const FromType& input) 413 421 { 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 422 427 template<class FromType, class ToType> 423 staticbool ConvertValue(ToType* output, const FromType& input)428 inline bool ConvertValue(ToType* output, const FromType& input) 424 429 { 425 430 return convertValue(output, input); 426 431 } 432 433 // Calls convertValue and returns true if the conversion was successful. 434 // Otherwise the fallback is used. 427 435 template<class FromType, class ToType> 428 staticbool ConvertValue(ToType* output, const FromType& input, const ToType& fallback)436 inline bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback) 429 437 { 430 438 if (convertValue(output, input)) … … 435 443 } 436 444 437 // Helper function: Calls convertValue with and without default value and returns the converted value445 // Directly returns the converted value, even if the conversion was not successful. 438 446 template<class FromType, class ToType> 439 staticToType getConvertedValue(const FromType& input)440 { 441 ToType output = ToType();447 inline ToType getConvertedValue(const FromType& input) 448 { 449 ToType output; 442 450 ConvertValue(&output, input); 443 451 return output; 444 452 } 453 454 // Directly returns the converted value, but uses the fallback on failure. 445 455 template<class FromType, class ToType> 446 staticToType getConvertedValue(const FromType& input, const ToType& fallback)456 inline ToType getConvertedValue(const FromType& input, const ToType& fallback) 447 457 { 448 458 ToType output = fallback; … … 451 461 } 452 462 463 // Like getConvertedValue, but the template argument order is in reverse. 464 // That means you can call it exactly like static_cast<ToType>(fromTypeValue). 465 template<class ToType, class FromType> 466 inline 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. 474 template<class ToType, class FromType> 475 inline 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 488 template <class ToType> 489 struct 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 499 template <> 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 }; 507 template <> 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 }; 515 template <> 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 }; 526 template <> 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 453 538 #endif /* _Convert_H__ */
Note: See TracChangeset
for help on using the changeset viewer.