1 /// @file 2 // Boost.Convert 3 // Copyright (c) 2009-2016 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 boost::throw_on_failure is the 'tag' object 36 /// to request the exception-throwing behavior. 37 detail::throw_on_failure const throw_on_failure = detail::throw_on_failure(0); 38 39 namespace cnv 40 { 41 template<typename, typename, typename> struct reference; 42 struct by_default; 43 } 44 45 /// @brief Boost.Convert main deployment interface 46 /// @param[in] value_in Value of the TypeIn type to be converted to the TypeOut type 47 /// @param[in] converter Converter to be used for conversion 48 /// @return boost::optional<TypeOut> result of conversion together with the indication of 49 /// success or failure of the conversion request. 50 /// @details For example, 51 /// @code 52 /// boost::cnv::cstream cnv; 53 /// 54 /// boost::optional<int> i = boost::convert<int>("12", cnv); 55 /// boost::optional<string> s = boost::convert<string>(123.456, cnv); 56 /// @endcode 57 58 template<typename TypeOut, typename TypeIn, typename Converter> 59 boost::optional<TypeOut> convert(TypeIn const & value_in,Converter const & converter)60 convert(TypeIn const& value_in, Converter const& converter) 61 { 62 optional<TypeOut> result; 63 boost::unwrap_ref(converter)(value_in, result); 64 return result; 65 } 66 67 namespace cnv { namespace detail 68 { 69 template<typename TypeOut, typename TypeIn, typename Converter =boost::cnv::by_default> 70 struct delayed_resolution 71 { convertboost::cnv::detail::delayed_resolution72 static optional<TypeOut> convert(TypeIn const& value_in) 73 { 74 return boost::convert<TypeOut>(value_in, Converter()); 75 } 76 }; 77 }} 78 /// @brief Boost.Convert deployment interface with the default converter 79 /// @details For example, 80 /// @code 81 /// struct boost::cnv::by_default : boost::cnv::cstream {}; 82 /// 83 /// // boost::cnv::cstream (through boost::cnv::by_default) is deployed 84 /// // as the default converter when no converter is provided explicitly. 85 /// boost::optional<int> i = boost::convert<int>("12"); 86 /// boost::optional<string> s = boost::convert<string>(123.456); 87 /// @endcode 88 89 template<typename TypeOut, typename TypeIn> 90 boost::optional<TypeOut> convert(TypeIn const & value_in)91 convert(TypeIn const& value_in) 92 { 93 return cnv::detail::delayed_resolution<TypeOut, TypeIn>::convert(value_in); 94 } 95 } 96 97 namespace boost 98 { 99 /// @brief Boost.Convert non-optional deployment interface 100 101 template<typename TypeOut, typename TypeIn, typename Converter> 102 TypeOut convert(TypeIn const & value_in,Converter const & converter,boost::detail::throw_on_failure)103 convert(TypeIn const& value_in, Converter const& converter, boost::detail::throw_on_failure) 104 { 105 return convert<TypeOut>(value_in, converter).value(); 106 } 107 108 template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback> 109 typename enable_if<is_convertible<Fallback, TypeOut>, TypeOut>::type convert(TypeIn const & value_in,Converter const & converter,Fallback const & fallback)110 convert(TypeIn const& value_in, Converter const& converter, Fallback const& fallback) 111 { 112 return convert<TypeOut>(value_in, converter).value_or(fallback); 113 } 114 115 template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback> 116 typename enable_if<cnv::is_fun<Fallback, TypeOut>, TypeOut>::type convert(TypeIn const & value_in,Converter const & converter,Fallback fallback)117 convert(TypeIn const& value_in, Converter const& converter, Fallback fallback) 118 { 119 return convert<TypeOut>(value_in, converter).value_or_eval(fallback); 120 } 121 } 122 123 namespace boost { namespace cnv 124 { 125 template<typename Converter, typename TypeOut, typename TypeIn> 126 struct reference 127 { 128 typedef reference this_type; 129 referenceboost::cnv::reference130 reference(Converter const& cnv) : converter_(cnv) {} 131 132 #ifdef BOOST_CONVERT_CXX11 referenceboost::cnv::reference133 reference(Converter&& cnv) : converter_(std::move(cnv)) {} 134 #endif 135 136 this_type& value_orboost::cnv::reference137 value_or(TypeOut const& fallback) 138 { 139 return (fallback_ = fallback, *this); 140 } 141 142 TypeOut operator ()boost::cnv::reference143 operator()(TypeIn const& value_in) 144 { 145 optional<TypeOut> result = convert<TypeOut>(value_in, converter_); 146 return result ? result.get() : fallback_.value(); 147 } 148 149 private: 150 151 Converter converter_; 152 optional<TypeOut> fallback_; 153 }; 154 template<typename Converter, typename TypeOut> 155 struct reference<Converter, TypeOut, void> 156 { 157 typedef reference this_type; 158 referenceboost::cnv::reference159 reference(Converter const& cnv) : converter_(cnv) {} 160 161 #ifdef BOOST_CONVERT_CXX11 referenceboost::cnv::reference162 reference(Converter&& cnv) : converter_(std::move(cnv)) {} 163 #endif 164 165 this_type& value_orboost::cnv::reference166 value_or(TypeOut const& fallback) 167 { 168 return (fallback_ = fallback, *this); 169 } 170 171 template<typename TypeIn> 172 TypeOut operator ()boost::cnv::reference173 operator()(TypeIn const& value_in) 174 { 175 optional<TypeOut> result = convert<TypeOut>(value_in, converter_); 176 return result ? result.get() : fallback_.value(); 177 } 178 179 private: 180 181 Converter converter_; 182 optional<TypeOut> fallback_; 183 }; 184 185 /// @brief Boost.Convert deployment interface with algorithms 186 /// @details For example, 187 /// @code 188 /// boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }}; 189 /// std::vector<int> ints; 190 /// boost::cnv::cstream cnv; 191 /// 192 /// cnv(std::hex)(std::skipws); 193 /// 194 /// std::transform( 195 /// strs.begin(), 196 /// strs.end(), 197 /// std::back_inserter(ints), 198 /// boost::cnv::apply<int>(boost::cref(cnv)).value_or(-1)); 199 /// @endcode 200 201 template<typename TypeOut, typename TypeIn, typename Converter> 202 reference<Converter, TypeOut, TypeIn> apply(Converter const & cnv)203 apply(Converter const& cnv) 204 { 205 return cnv::reference<Converter, TypeOut, TypeIn>(cnv); 206 } 207 template<typename TypeOut, typename Converter> 208 reference<Converter, TypeOut, void> apply(Converter const & cnv)209 apply(Converter const& cnv) 210 { 211 return cnv::reference<Converter, TypeOut, void>(cnv); 212 } 213 }} 214 215 #endif // BOOST_CONVERT_HPP 216