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