1 /// @file 2 // Boost.Convert 3 // Copyright (c) 2009-2014 Vladimir Batov. 4 // 5 // Many thanks to Julian Gonggrijp, Rob Stewart, Andrzej Krzemienski, Matus Chochlik, Jeroen Habraken, 6 // Hartmut Kaiser, Joel De Guzman, Thijs (M.A.) van den Berg, Roland Bock, Gavin Lambert, Paul Bristow, 7 // Alex Hagen-Zanker, Christopher Kormanyos for taking part in the Boost.Convert review. 8 // 9 // Special thanks to: 10 // 11 // 1. Alex Hagen-Zanker, Roland Bock, Rob Stewart for their considerable contributions to the design 12 // and implementation of the library; 13 // 2. Andrzej Krzemienski for helping to partition responsibilities and to ultimately pave 14 // the way for the boost::optional and future std::tr2::optional deployment; 15 // 3. Edward Diener the Boost Review Manager for helping with the converters' design, his continuous 16 // involvement, technical and administrative help, guidance and advice; 17 // 4. Joel De Guzman, Rob Stewart and Alex Hagen-Zanker for making sure the performance tests work 18 // as they should; 19 // 5. Paul Bristow for helping great deal with the documentation; 20 // 6. Kevlin Henney and Dave Abrahams for their lexical_cast-related insights and explanations. 21 // 22 // Use, modification and distribution are subject to the Boost Software License, 23 // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. 24 25 #ifndef BOOST_CONVERT_HPP 26 #define BOOST_CONVERT_HPP 27 28 #include <boost/convert/detail/is_fun.hpp> 29 #include <boost/ref.hpp> 30 31 namespace boost 32 { 33 namespace detail { enum throw_on_failure {}; } 34 35 /// @details The boost::throw_on_failure is the name of an object of the 36 /// boost::detail::throw_on_failure type that is used to indicate 37 /// desired exception-throwing behavior. 38 detail::throw_on_failure const throw_on_failure = detail::throw_on_failure(0); 39 40 namespace cnv 41 { 42 template<typename, typename, typename> struct reference; 43 struct by_default; 44 } 45 46 /// @brief Boost.Convert main deployment interface 47 /// @param[in] value_in Value of the TypeIn type to be converted to the TyeOut type 48 /// @param[in] converter Converter to be used for conversion 49 /// @return boost::optional<TypeOut> result of conversion together with the indication of 50 /// success or failure of the conversion request. 51 /// @details For example, 52 /// @code 53 /// boost::cnv::cstream cnv; 54 /// 55 /// boost::optional<int> i = boost::convert<int>("12", cnv); 56 /// boost::optional<string> s = boost::convert<string>(123.456, cnv); 57 /// @endcode 58 59 template<typename TypeOut, typename TypeIn, typename Converter> 60 boost::optional<TypeOut> convert(TypeIn const & value_in,Converter const & converter)61 convert(TypeIn const& value_in, Converter const& converter) 62 { 63 optional<TypeOut> result; 64 boost::unwrap_ref(converter)(value_in, result); 65 return result; 66 } 67 68 namespace cnv { namespace detail 69 { 70 template<typename TypeOut, typename TypeIn, typename Converter =boost::cnv::by_default> 71 struct delayed_resolution 72 { convertboost::cnv::detail::delayed_resolution73 static optional<TypeOut> convert(TypeIn const& value_in) 74 { 75 return boost::convert<TypeOut>(value_in, Converter()); 76 } 77 }; 78 }} 79 /// @brief Boost.Convert deployment interface with the default converter 80 /// @details For example, 81 /// @code 82 /// struct boost::cnv::by_default : public boost::cnv::cstream {}; 83 /// 84 /// // boost::cnv::cstream (through boost::cnv::by_default) is deployed 85 /// // as the default converter when no converter is provided explicitly. 86 /// boost::optional<int> i = boost::convert<int>("12"); 87 /// boost::optional<string> s = boost::convert<string>(123.456); 88 /// @endcode 89 90 template<typename TypeOut, typename TypeIn> 91 boost::optional<TypeOut> convert(TypeIn const & value_in)92 convert(TypeIn const& value_in) 93 { 94 return cnv::detail::delayed_resolution<TypeOut, TypeIn>::convert(value_in); 95 } 96 } 97 98 namespace boost 99 { 100 /// @brief Boost.Convert non-optional deployment interface 101 102 template<typename TypeOut, typename TypeIn, typename Converter> 103 TypeOut 104 convert(TypeIn const& value_in, Converter const& converter, boost::detail::throw_on_failure) 105 { 106 return convert<TypeOut>(value_in, converter).value(); 107 } 108 109 template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback> 110 typename enable_if<is_convertible<Fallback, TypeOut>, TypeOut>::type convert(TypeIn const & value_in,Converter const & converter,Fallback const & fallback)111 convert(TypeIn const& value_in, Converter const& converter, Fallback const& fallback) 112 { 113 return convert<TypeOut>(value_in, converter).value_or(fallback); 114 } 115 116 template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback> 117 typename enable_if<cnv::is_fun<Fallback, TypeOut>, TypeOut>::type convert(TypeIn const & value_in,Converter const & converter,Fallback fallback)118 convert(TypeIn const& value_in, Converter const& converter, Fallback fallback) 119 { 120 return convert<TypeOut>(value_in, converter).value_or_eval(fallback); 121 } 122 } 123 124 namespace boost { namespace cnv 125 { 126 template<typename Converter, typename TypeOut, typename TypeIn> 127 struct reference 128 { 129 typedef reference this_type; 130 referenceboost::cnv::reference131 reference(Converter const& cnv) : converter_(cnv) {} 132 133 #ifdef BOOST_CONVERT_CXX11 referenceboost::cnv::reference134 reference(Converter&& cnv) : converter_(std::move(cnv)) {} 135 #endif 136 137 this_type& value_orboost::cnv::reference138 value_or(TypeOut const& fallback) 139 { 140 return (fallback_ = fallback, *this); 141 } 142 143 TypeOut operator ()boost::cnv::reference144 operator()(TypeIn const& value_in) 145 { 146 optional<TypeOut> result = convert<TypeOut>(value_in, converter_); 147 return result ? result.get() : fallback_.value(); 148 } 149 150 private: 151 152 Converter converter_; 153 optional<TypeOut> fallback_; 154 }; 155 template<typename Converter, typename TypeOut> 156 struct reference<Converter, TypeOut, void> 157 { 158 typedef reference this_type; 159 referenceboost::cnv::reference160 reference(Converter const& cnv) : converter_(cnv) {} 161 162 #ifdef BOOST_CONVERT_CXX11 referenceboost::cnv::reference163 reference(Converter&& cnv) : converter_(std::move(cnv)) {} 164 #endif 165 166 this_type& value_orboost::cnv::reference167 value_or(TypeOut const& fallback) 168 { 169 return (fallback_ = fallback, *this); 170 } 171 172 template<typename TypeIn> 173 TypeOut operator ()boost::cnv::reference174 operator()(TypeIn const& value_in) 175 { 176 optional<TypeOut> result = convert<TypeOut>(value_in, converter_); 177 return result ? result.get() : fallback_.value(); 178 } 179 180 private: 181 182 Converter converter_; 183 optional<TypeOut> fallback_; 184 }; 185 186 /// @brief Boost.Convert deployment interface with algorithms 187 /// @details For example, 188 /// @code 189 /// boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }}; 190 /// std::vector<int> ints; 191 /// boost::cnv::cstream cnv; 192 /// 193 /// cnv(std::hex)(std::skipws); 194 /// 195 /// std::transform( 196 /// strs.begin(), 197 /// strs.end(), 198 /// std::back_inserter(ints), 199 /// boost::cnv::apply<int>(boost::cref(cnv)).value_or(-1)); 200 /// @endcode 201 202 template<typename TypeOut, typename TypeIn, typename Converter> 203 reference<Converter, TypeOut, TypeIn> apply(Converter const & cnv)204 apply(Converter const& cnv) 205 { 206 return cnv::reference<Converter, TypeOut, TypeIn>(cnv); 207 } 208 template<typename TypeOut, typename Converter> 209 reference<Converter, TypeOut, void> apply(Converter const & cnv)210 apply(Converter const& cnv) 211 { 212 return cnv::reference<Converter, TypeOut, void>(cnv); 213 } 214 }} 215 216 #endif // BOOST_CONVERT_HPP 217