convert.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /// @file
  2. // Boost.Convert
  3. // Copyright (c) 2009-2020 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. #ifndef BOOST_CONVERT_HPP
  25. #define BOOST_CONVERT_HPP
  26. #include <boost/convert/detail/is_fun.hpp>
  27. #include <boost/core/ref.hpp>
  28. namespace boost
  29. {
  30. namespace detail { enum throw_on_failure {}; }
  31. /// @details boost::throw_on_failure is the 'tag' object
  32. /// to request the exception-throwing behavior.
  33. detail::throw_on_failure const throw_on_failure = detail::throw_on_failure(0);
  34. namespace cnv
  35. {
  36. template<typename, typename, typename> struct reference;
  37. struct by_default;
  38. }
  39. /// @brief Boost.Convert main deployment interface
  40. /// @param[in] value_in Value of the TypeIn type to be converted to the TypeOut type
  41. /// @param[in] converter Converter to be used for conversion
  42. /// @return boost::optional<TypeOut> result of conversion together with the indication of
  43. /// success or failure of the conversion request.
  44. /// @details For example,
  45. /// @code
  46. /// boost::cnv::cstream cnv;
  47. ///
  48. /// boost::optional<int> i = boost::convert<int>("12", cnv);
  49. /// boost::optional<string> s = boost::convert<string>(123.456, cnv);
  50. /// @endcode
  51. template<typename TypeOut, typename TypeIn, typename Converter>
  52. boost::optional<TypeOut>
  53. convert(TypeIn const& value_in, Converter const& converter)
  54. {
  55. optional<TypeOut> result;
  56. boost::unwrap_ref(converter)(value_in, result);
  57. return result;
  58. }
  59. namespace cnv { namespace detail
  60. {
  61. template<typename TypeOut, typename TypeIn, typename Converter =boost::cnv::by_default>
  62. struct delayed_resolution
  63. {
  64. static optional<TypeOut> convert(TypeIn const& value_in)
  65. {
  66. return boost::convert<TypeOut>(value_in, Converter());
  67. }
  68. };
  69. }}
  70. /// @brief Boost.Convert deployment interface with the default converter
  71. /// @details For example,
  72. /// @code
  73. /// struct boost::cnv::by_default : boost::cnv::cstream {};
  74. ///
  75. /// // boost::cnv::cstream (through boost::cnv::by_default) is deployed
  76. /// // as the default converter when no converter is provided explicitly.
  77. /// boost::optional<int> i = boost::convert<int>("12");
  78. /// boost::optional<string> s = boost::convert<string>(123.456);
  79. /// @endcode
  80. template<typename TypeOut, typename TypeIn>
  81. boost::optional<TypeOut>
  82. convert(TypeIn const& value_in)
  83. {
  84. return cnv::detail::delayed_resolution<TypeOut, TypeIn>::convert(value_in);
  85. }
  86. }
  87. namespace boost
  88. {
  89. /// @brief Boost.Convert non-optional deployment interface
  90. template<typename TypeOut, typename TypeIn, typename Converter>
  91. TypeOut
  92. convert(TypeIn const& value_in, Converter const& converter, boost::detail::throw_on_failure)
  93. {
  94. return convert<TypeOut>(value_in, converter).value();
  95. }
  96. template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback>
  97. typename std::enable_if<is_convertible<Fallback, TypeOut>::value, TypeOut>::type
  98. convert(TypeIn const& value_in, Converter const& converter, Fallback const& fallback)
  99. {
  100. return convert<TypeOut>(value_in, converter).value_or(fallback);
  101. }
  102. template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback>
  103. typename std::enable_if<cnv::is_fun<Fallback, TypeOut>::value, TypeOut>::type
  104. convert(TypeIn const& value_in, Converter const& converter, Fallback fallback)
  105. {
  106. return convert<TypeOut>(value_in, converter).value_or_eval(fallback);
  107. }
  108. }
  109. namespace boost { namespace cnv
  110. {
  111. template<typename Converter, typename TypeOut, typename TypeIn>
  112. struct reference
  113. {
  114. using this_type = reference;
  115. reference (Converter const& cnv) : converter_(cnv) {}
  116. reference (Converter&& cnv) : converter_(std::move(cnv)) {}
  117. this_type&
  118. value_or(TypeOut const& fallback)
  119. {
  120. return (fallback_ = fallback, *this);
  121. }
  122. TypeOut
  123. operator()(TypeIn const& value_in) const
  124. {
  125. optional<TypeOut> result = convert<TypeOut>(value_in, converter_);
  126. return result ? result.get() : fallback_.value();
  127. }
  128. private:
  129. Converter converter_;
  130. optional<TypeOut> fallback_;
  131. };
  132. template<typename Converter, typename TypeOut>
  133. struct reference<Converter, TypeOut, void>
  134. {
  135. using this_type = reference;
  136. reference (Converter const& cnv) : converter_(cnv) {}
  137. reference (Converter&& cnv) : converter_(std::move(cnv)) {}
  138. this_type&
  139. value_or(TypeOut const& fallback)
  140. {
  141. return (fallback_ = fallback, *this);
  142. }
  143. template<typename TypeIn>
  144. TypeOut
  145. operator()(TypeIn const& value_in) const
  146. {
  147. optional<TypeOut> result = convert<TypeOut>(value_in, converter_);
  148. return result ? result.get() : fallback_.value();
  149. }
  150. private:
  151. Converter converter_;
  152. optional<TypeOut> fallback_;
  153. };
  154. /// @brief Boost.Convert deployment interface with algorithms
  155. /// @details For example,
  156. /// @code
  157. /// std::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
  158. /// std::vector<int> ints;
  159. /// boost::cnv::cstream cnv;
  160. ///
  161. /// cnv(std::hex)(std::skipws);
  162. ///
  163. /// std::transform(
  164. /// strs.begin(),
  165. /// strs.end(),
  166. /// std::back_inserter(ints),
  167. /// boost::cnv::apply<int>(std::cref(cnv)).value_or(-1));
  168. /// @endcode
  169. template<typename TypeOut, typename TypeIn, typename Converter>
  170. reference<Converter, TypeOut, TypeIn>
  171. apply(Converter const& cnv)
  172. {
  173. return cnv::reference<Converter, TypeOut, TypeIn>(cnv);
  174. }
  175. template<typename TypeOut, typename Converter>
  176. reference<Converter, TypeOut, void>
  177. apply(Converter const& cnv)
  178. {
  179. return cnv::reference<Converter, TypeOut, void>(cnv);
  180. }
  181. }}
  182. #endif // BOOST_CONVERT_HPP