]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
22 | #if defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_HDR_TUPLE) | |
23 | # error "This file requires <tuple> and variadic templates support" | |
24 | #endif | |
25 | ||
26 | #include <tuple> | |
27 | ||
28 | namespace boost { | |
29 | ||
30 | namespace detail { namespace variant { | |
31 | ||
32 | // Implementing some of the C++14 features in C++11 | |
33 | template <std::size_t... I> class index_sequence {}; | |
34 | ||
35 | template <std::size_t N, std::size_t... I> | |
36 | struct make_index_sequence | |
37 | : make_index_sequence<N-1, N-1, I...> | |
38 | {}; | |
39 | template <std::size_t... I> | |
40 | struct make_index_sequence<0, I...> | |
41 | : index_sequence<I...> | |
42 | {}; | |
43 | ||
44 | template <class... Types> | |
45 | std::tuple<Types&...> forward_as_tuple_simple(Types&... args) BOOST_NOEXCEPT | |
46 | { | |
47 | return std::tuple<Types&...>(args...); | |
48 | } | |
49 | ||
50 | // Implementing some of the helper tuple methods | |
51 | template <std::size_t... I, typename Tuple> | |
52 | std::tuple<typename std::tuple_element<I + 1, Tuple>::type...> | |
53 | tuple_tail_impl(const Tuple& tpl, index_sequence<I...>) | |
54 | { | |
55 | return std::tuple< | |
56 | typename std::tuple_element<I + 1, Tuple>::type... | |
57 | > (std::get<I + 1>(tpl)...); | |
58 | } | |
59 | ||
60 | template <typename Head, typename... Tail> | |
61 | std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& tpl) | |
62 | { | |
63 | return tuple_tail_impl(tpl, make_index_sequence<sizeof...(Tail)>()); | |
64 | } | |
65 | ||
66 | ||
67 | ||
68 | // Forward declaration | |
69 | template <typename Visitor, typename Visitables, typename... Values> | |
70 | class one_by_one_visitor_and_value_referer; | |
71 | ||
72 | template <typename Visitor, typename Visitables, typename... Values> | |
73 | inline one_by_one_visitor_and_value_referer<Visitor, Visitables, Values... > | |
74 | make_one_by_one_visitor_and_value_referer( | |
75 | Visitor& visitor, Visitables visitables, std::tuple<Values&...> values | |
76 | ) | |
77 | { | |
78 | return one_by_one_visitor_and_value_referer<Visitor, Visitables, Values... > ( | |
79 | visitor, visitables, values | |
80 | ); | |
81 | } | |
82 | ||
83 | template <typename Visitor, typename Visitables, typename... Values> | |
84 | class one_by_one_visitor_and_value_referer | |
85 | { | |
86 | Visitor& visitor_; | |
87 | std::tuple<Values&...> values_; | |
88 | Visitables visitables_; | |
89 | ||
90 | public: // structors | |
91 | one_by_one_visitor_and_value_referer( | |
92 | Visitor& visitor, Visitables visitables, std::tuple<Values&...> values | |
93 | ) BOOST_NOEXCEPT | |
94 | : visitor_(visitor) | |
95 | , values_(values) | |
96 | , visitables_(visitables) | |
97 | {} | |
98 | ||
99 | public: // visitor interfaces | |
100 | typedef typename Visitor::result_type result_type; | |
101 | ||
102 | template <typename Value> | |
103 | BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value& value) const | |
104 | { | |
105 | return ::boost::apply_visitor( | |
106 | make_one_by_one_visitor_and_value_referer( | |
107 | visitor_, | |
108 | tuple_tail(visitables_), | |
109 | std::tuple_cat(values_, std::tuple<Value&>(value)) | |
110 | ) | |
111 | , std::get<0>(visitables_) // getting Head element | |
112 | ); | |
113 | } | |
114 | ||
115 | private: | |
116 | one_by_one_visitor_and_value_referer& operator=(const one_by_one_visitor_and_value_referer&); | |
117 | }; | |
118 | ||
119 | template <typename Visitor, typename... Values> | |
120 | class one_by_one_visitor_and_value_referer<Visitor, std::tuple<>, Values...> | |
121 | { | |
122 | Visitor& visitor_; | |
123 | std::tuple<Values&...> values_; | |
124 | ||
125 | public: | |
126 | one_by_one_visitor_and_value_referer( | |
127 | Visitor& visitor, std::tuple<> /*visitables*/, std::tuple<Values&...> values | |
128 | ) BOOST_NOEXCEPT | |
129 | : visitor_(visitor) | |
130 | , values_(values) | |
131 | {} | |
132 | ||
133 | typedef typename Visitor::result_type result_type; | |
134 | ||
135 | template <class Tuple, std::size_t... I> | |
136 | BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) do_call(Tuple t, index_sequence<I...>) const { | |
137 | return visitor_(std::get<I>(t)...); | |
138 | } | |
139 | ||
140 | template <typename Value> | |
141 | BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value& value) const | |
142 | { | |
143 | return do_call( | |
144 | std::tuple_cat(values_, std::tuple<Value&>(value)), | |
145 | make_index_sequence<sizeof...(Values) + 1>() | |
146 | ); | |
147 | } | |
148 | }; | |
149 | ||
150 | }} // namespace detail::variant | |
151 | ||
152 | template <class Visitor, class T1, class T2, class T3, class... TN> | |
153 | inline BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) | |
154 | apply_visitor(const Visitor& visitor, T1& v1, T2& v2, T3& v3, TN&... vn) | |
155 | { | |
156 | return ::boost::apply_visitor( | |
157 | ::boost::detail::variant::make_one_by_one_visitor_and_value_referer( | |
158 | visitor, | |
159 | ::boost::detail::variant::forward_as_tuple_simple(v2, v3, vn...), | |
160 | std::tuple<>() | |
161 | ), | |
162 | v1 | |
163 | ); | |
164 | } | |
165 | ||
166 | template <class Visitor, class T1, class T2, class T3, class... TN> | |
167 | inline BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) | |
168 | apply_visitor(Visitor& visitor, T1& v1, T2& v2, T3& v3, TN&... vn) | |
169 | { | |
170 | return ::boost::apply_visitor( | |
171 | ::boost::detail::variant::make_one_by_one_visitor_and_value_referer( | |
172 | visitor, | |
173 | ::boost::detail::variant::forward_as_tuple_simple(v2, v3, vn...), | |
174 | std::tuple<>() | |
175 | ), | |
176 | v1 | |
177 | ); | |
178 | } | |
179 | ||
180 | } // namespace boost | |
181 | ||
182 | #endif // BOOST_VARIANT_DETAIL_MULTIVISITORS_CPP11_BASED_HPP | |
183 |