• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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