1 // Boost.Varaint 2 // Contains multivisitors that are implemented via variadic templates and std::tuple 3 // 4 // See http://www.boost.org for most recent version, including documentation. 5 // 6 // Copyright Antony Polukhin, 2013-2014. 7 // 8 // Distributed under the Boost 9 // Software License, Version 1.0. (See accompanying file 10 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). 11 12 #ifndef BOOST_VARIANT_DETAIL_MULTIVISITORS_CPP11_BASED_HPP 13 #define BOOST_VARIANT_DETAIL_MULTIVISITORS_CPP11_BASED_HPP 14 15 #if defined(_MSC_VER) 16 # pragma once 17 #endif 18 19 #include <boost/variant/detail/apply_visitor_unary.hpp> 20 #include <boost/variant/variant_fwd.hpp> // for BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES 21 #include <boost/move/utility.hpp> 22 #include <boost/type_traits/is_lvalue_reference.hpp> 23 #include <boost/core/enable_if.hpp> 24 25 #if defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_HDR_TUPLE) 26 # error "This file requires <tuple> and variadic templates support" 27 #endif 28 29 #include <tuple> 30 31 namespace boost { 32 33 namespace detail { namespace variant { 34 35 // Implementing some of the C++14 features in C++11 36 template <std::size_t... I> class index_sequence {}; 37 38 template <std::size_t N, std::size_t... I> 39 struct make_index_sequence 40 : make_index_sequence<N-1, N-1, I...> 41 {}; 42 template <std::size_t... I> 43 struct make_index_sequence<0, I...> 44 : index_sequence<I...> 45 {}; 46 47 template <typename T_, bool MoveSemantics_> 48 struct MoveableWrapper //Just a reference with some metadata 49 { 50 typedef T_ T; 51 static constexpr bool MoveSemantics = MoveSemantics_; 52 53 T& v; 54 }; 55 56 template <typename Tp, bool MoveSemantics> 57 MoveableWrapper<Tp, MoveSemantics> wrap(Tp & t)58 wrap(Tp& t) 59 { 60 return MoveableWrapper<Tp, MoveSemantics>{t}; 61 } 62 63 template <typename Wrapper> 64 typename enable_if_c<Wrapper::MoveSemantics, typename Wrapper::T>::type unwrap(Wrapper & w)65 unwrap(Wrapper& w) 66 { 67 return ::boost::move(w.v); 68 } 69 70 template <typename Wrapper> 71 typename disable_if_c<Wrapper::MoveSemantics, typename Wrapper::T>::type & unwrap(Wrapper & w)72 unwrap(Wrapper& w) 73 { 74 return w.v; 75 } 76 77 // Implementing some of the helper tuple methods 78 template <std::size_t... I, typename Tuple> 79 std::tuple<typename std::tuple_element<I + 1, Tuple>::type...> tuple_tail_impl(const Tuple & tpl,index_sequence<I...>)80 tuple_tail_impl(const Tuple& tpl, index_sequence<I...>) 81 { 82 return std::tuple< 83 typename std::tuple_element<I + 1, Tuple>::type... 84 > (std::get<I + 1>(tpl)...); 85 } 86 87 template <typename Head, typename... Tail> tuple_tail(const std::tuple<Head,Tail...> & tpl)88 std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& tpl) 89 { 90 return tuple_tail_impl(tpl, make_index_sequence<sizeof...(Tail)>()); 91 } 92 93 94 // Forward declaration 95 template <typename Visitor, typename Visitables, typename... Values> 96 class one_by_one_visitor_and_value_referer; 97 98 template <typename Visitor, typename Visitables, typename... Values> 99 inline one_by_one_visitor_and_value_referer<Visitor, Visitables, Values... > make_one_by_one_visitor_and_value_referer(Visitor & visitor,Visitables visitables,std::tuple<Values...> values)100 make_one_by_one_visitor_and_value_referer( 101 Visitor& visitor, Visitables visitables, std::tuple<Values...> values 102 ) 103 { 104 return one_by_one_visitor_and_value_referer<Visitor, Visitables, Values... > ( 105 visitor, visitables, values 106 ); 107 } 108 109 template <typename Visitor, typename Visitables, typename... Values> 110 class one_by_one_visitor_and_value_referer 111 { 112 Visitor& visitor_; 113 std::tuple<Values...> values_; 114 Visitables visitables_; 115 116 public: // structors one_by_one_visitor_and_value_referer(Visitor & visitor,Visitables visitables,std::tuple<Values...> values)117 one_by_one_visitor_and_value_referer( 118 Visitor& visitor, Visitables visitables, std::tuple<Values...> values 119 ) BOOST_NOEXCEPT 120 : visitor_(visitor) 121 , values_(values) 122 , visitables_(visitables) 123 {} 124 125 public: // visitor interfaces 126 typedef typename Visitor::result_type result_type; 127 128 template <typename Value> operator ()(Value && value) const129 result_type operator()(Value&& value) const 130 { 131 return ::boost::apply_visitor( 132 make_one_by_one_visitor_and_value_referer( 133 visitor_, 134 tuple_tail(visitables_), 135 std::tuple_cat(values_, std::make_tuple(wrap<Value, ! ::boost::is_lvalue_reference<Value>::value>(value))) 136 ) 137 , unwrap(std::get<0>(visitables_)) // getting Head element 138 ); 139 } 140 141 private: 142 one_by_one_visitor_and_value_referer& operator=(const one_by_one_visitor_and_value_referer&); 143 }; 144 145 template <typename Visitor, typename... Values> 146 class one_by_one_visitor_and_value_referer<Visitor, std::tuple<>, Values...> 147 { 148 Visitor& visitor_; 149 std::tuple<Values...> values_; 150 151 public: 152 one_by_one_visitor_and_value_referer( 153 Visitor& visitor, std::tuple<> /*visitables*/, std::tuple<Values...> values 154 ) BOOST_NOEXCEPT 155 : visitor_(visitor) 156 , values_(values) 157 {} 158 159 typedef typename Visitor::result_type result_type; 160 161 template <class Tuple, std::size_t... I> 162 result_type do_call(Tuple t, index_sequence<I...>) const { 163 return visitor_(unwrap(std::get<I>(t))...); 164 } 165 166 template <typename Value> 167 result_type operator()(Value&& value) const 168 { 169 return do_call( 170 std::tuple_cat(values_, std::make_tuple(wrap<Value, ! ::boost::is_lvalue_reference<Value>::value>(value))), 171 make_index_sequence<sizeof...(Values) + 1>() 172 ); 173 } 174 }; 175 176 }} // namespace detail::variant 177 178 template <class Visitor, class T1, class T2, class T3, class... TN> 179 inline typename Visitor::result_type apply_visitor(const Visitor & visitor,T1 && v1,T2 && v2,T3 && v3,TN &&...vn)180 apply_visitor(const Visitor& visitor, T1&& v1, T2&& v2, T3&& v3, TN&&... vn) 181 { 182 return ::boost::apply_visitor( 183 ::boost::detail::variant::make_one_by_one_visitor_and_value_referer( 184 visitor, 185 std::make_tuple( 186 ::boost::detail::variant::wrap<T2, ! ::boost::is_lvalue_reference<T2>::value>(v2), 187 ::boost::detail::variant::wrap<T3, ! ::boost::is_lvalue_reference<T3>::value>(v3), 188 ::boost::detail::variant::wrap<TN, ! ::boost::is_lvalue_reference<TN>::value>(vn)... 189 ), 190 std::tuple<>() 191 ), 192 ::boost::forward<T1>(v1) 193 ); 194 } 195 196 template <class Visitor, class T1, class T2, class T3, class... TN> 197 inline typename Visitor::result_type apply_visitor(Visitor & visitor,T1 && v1,T2 && v2,T3 && v3,TN &&...vn)198 apply_visitor(Visitor& visitor, T1&& v1, T2&& v2, T3&& v3, TN&&... vn) 199 { 200 return ::boost::apply_visitor( 201 ::boost::detail::variant::make_one_by_one_visitor_and_value_referer( 202 visitor, 203 std::make_tuple( 204 ::boost::detail::variant::wrap<T2, ! ::boost::is_lvalue_reference<T2>::value>(v2), 205 ::boost::detail::variant::wrap<T3, ! ::boost::is_lvalue_reference<T3>::value>(v3), 206 ::boost::detail::variant::wrap<TN, ! ::boost::is_lvalue_reference<TN>::value>(vn)... 207 ), 208 std::tuple<>() 209 ), 210 ::boost::forward<T1>(v1) 211 ); 212 } 213 214 } // namespace boost 215 216 #endif // BOOST_VARIANT_DETAIL_MULTIVISITORS_CPP11_BASED_HPP 217 218