apply_visitor_unary.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. //-----------------------------------------------------------------------------
  2. // boost variant/detail/apply_visitor_unary.hpp header file
  3. // See http://www.boost.org for updates, documentation, and revision history.
  4. //-----------------------------------------------------------------------------
  5. //
  6. // Copyright (c) 2002-2003 Eric Friedman
  7. // Copyright (c) 2014 Antony Polukhin
  8. //
  9. // Distributed under the Boost Software License, Version 1.0. (See
  10. // accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. #ifndef BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP
  13. #define BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP
  14. #include <boost/config.hpp>
  15. #include <boost/detail/workaround.hpp>
  16. #include <boost/variant/detail/generic_result_type.hpp>
  17. #include <boost/move/utility.hpp>
  18. #if BOOST_WORKAROUND(__EDG__, BOOST_TESTED_AT(302))
  19. #include <boost/core/enable_if.hpp>
  20. #include <boost/mpl/not.hpp>
  21. #include <boost/type_traits/is_const.hpp>
  22. #include <boost/type_traits/remove_reference.hpp>
  23. #endif
  24. #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
  25. # include <boost/mpl/distance.hpp>
  26. # include <boost/mpl/advance.hpp>
  27. # include <boost/mpl/deref.hpp>
  28. # include <boost/mpl/size.hpp>
  29. # include <boost/utility/declval.hpp>
  30. # include <boost/core/enable_if.hpp>
  31. # include <boost/variant/detail/has_result_type.hpp>
  32. #endif
  33. namespace boost {
  34. //////////////////////////////////////////////////////////////////////////
  35. // function template apply_visitor(visitor, visitable)
  36. //
  37. // Visits visitable with visitor.
  38. //
  39. //
  40. // nonconst-visitor version:
  41. //
  42. #if !BOOST_WORKAROUND(__EDG__, BOOST_TESTED_AT(302))
  43. # define BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(V) \
  44. BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename V::result_type) \
  45. /**/
  46. #else // EDG-based compilers
  47. # define BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(V) \
  48. typename enable_if< \
  49. mpl::not_< is_const< V > > \
  50. , BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename V::result_type) \
  51. >::type \
  52. /**/
  53. #endif // EDG-based compilers workaround
  54. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  55. template <typename Visitor, typename Visitable>
  56. inline
  57. BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
  58. apply_visitor(Visitor& visitor, Visitable&& visitable)
  59. {
  60. return ::boost::forward<Visitable>(visitable).apply_visitor(visitor);
  61. }
  62. #else
  63. template <typename Visitor, typename Visitable>
  64. inline
  65. BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
  66. apply_visitor(Visitor& visitor, Visitable& visitable)
  67. {
  68. return visitable.apply_visitor(visitor);
  69. }
  70. #endif
  71. #undef BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE
  72. //
  73. // const-visitor version:
  74. //
  75. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  76. template <typename Visitor, typename Visitable>
  77. inline
  78. BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
  79. apply_visitor(const Visitor& visitor, Visitable&& visitable)
  80. {
  81. return ::boost::forward<Visitable>(visitable).apply_visitor(visitor);
  82. }
  83. #else
  84. template <typename Visitor, typename Visitable>
  85. inline
  86. BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
  87. apply_visitor(const Visitor& visitor, Visitable& visitable)
  88. {
  89. return visitable.apply_visitor(visitor);
  90. }
  91. #endif
  92. #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
  93. // C++14
  94. namespace detail { namespace variant {
  95. // This class serves only metaprogramming purposes. none of its methods must be called at runtime!
  96. template <class Visitor, class Variant>
  97. struct result_multideduce1 {
  98. typedef typename Variant::types types;
  99. typedef typename boost::mpl::begin<types>::type begin_it;
  100. typedef typename boost::mpl::advance<
  101. begin_it, boost::mpl::int_<boost::mpl::size<types>::type::value - 1>
  102. >::type last_it;
  103. // For metaprogramming purposes ONLY! Do not use this method (and class) at runtime!
  104. static Visitor& vis() BOOST_NOEXCEPT {
  105. // Functions that work with lambdas must be defined in same translation unit.
  106. // Because of that, we can not use `boost::decval<Visitor&>()` here.
  107. Visitor&(*f)() = 0; // pointer to function
  108. return f();
  109. }
  110. static decltype(auto) deduce_impl(last_it, unsigned /*helper*/) {
  111. typedef typename boost::mpl::deref<last_it>::type value_t;
  112. return vis()( boost::declval< value_t& >() );
  113. }
  114. template <class It>
  115. static decltype(auto) deduce_impl(It, unsigned helper) {
  116. typedef typename boost::mpl::next<It>::type next_t;
  117. typedef typename boost::mpl::deref<It>::type value_t;
  118. if (helper == boost::mpl::distance<begin_it, It>::type::value) {
  119. return deduce_impl(next_t(), ++helper);
  120. }
  121. return vis()( boost::declval< value_t& >() );
  122. }
  123. static decltype(auto) deduce() {
  124. return deduce_impl(begin_it(), 0);
  125. }
  126. };
  127. template <class Visitor, class Variant>
  128. struct result_wrapper1
  129. {
  130. typedef decltype(result_multideduce1<Visitor, Variant>::deduce()) result_type;
  131. Visitor&& visitor_;
  132. explicit result_wrapper1(Visitor&& visitor) BOOST_NOEXCEPT
  133. : visitor_(::boost::forward<Visitor>(visitor))
  134. {}
  135. template <class T>
  136. result_type operator()(T&& val) const {
  137. return visitor_(::boost::forward<T>(val));
  138. }
  139. };
  140. }} // namespace detail::variant
  141. template <typename Visitor, typename Visitable>
  142. inline decltype(auto) apply_visitor(Visitor&& visitor, Visitable&& visitable,
  143. typename boost::disable_if<
  144. boost::detail::variant::has_result_type<Visitor>
  145. >::type* = 0)
  146. {
  147. boost::detail::variant::result_wrapper1<Visitor, typename remove_reference<Visitable>::type> cpp14_vis(::boost::forward<Visitor>(visitor));
  148. return ::boost::forward<Visitable>(visitable).apply_visitor(cpp14_vis);
  149. }
  150. #endif // !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
  151. } // namespace boost
  152. #endif // BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP