visitor.hpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2014, 2015 Ableton AG, Berlin. All rights reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21 //
22 
27 #pragma once
28 
31 #include <atria/meta/utils.hpp>
33 
34 #include <ableton/build_system/Warnings.hpp>
35 ABL_DISABLE_WARNINGS
36 #include <boost/mpl/push_back.hpp>
37 ABL_RESTORE_WARNINGS
38 
39 #include <cassert>
40 #include <utility>
41 
42 namespace atria {
43 namespace variant {
44 
45 namespace detail {
46 
47 template <typename ...Fns>
48 struct visitor_impl;
49 
50 template <typename Fn, typename ...Fns>
51 struct visitor_impl<Fn, Fns...>
52  : Fn
53  , visitor_impl<Fns...>
54 {
55  using next = visitor_impl<Fns...>;
56  using Fn::operator();
57  using next::operator();
58 
59  template <typename Fn2, typename ...Fns2>
60  visitor_impl(Fn2&& fn, Fns2&& ...fns)
61  : Fn(std::forward<Fn2>(fn))
62  , next(std::forward<Fns2>(fns)...)
63  {}
64 };
65 
66 template <typename Fn>
67 struct visitor_impl<Fn> : Fn
68 {
69  using Fn::operator();
70 
71  template <typename Fn2>
72  visitor_impl(Fn2&& fn)
73  : Fn(std::forward<Fn2>(fn))
74  {}
75 };
76 
77 } // namespace detail
78 
82 template <typename ReturnType, typename ...Fns>
83 class visitor_t
84 {
85  detail::visitor_impl<Fns...> impl_;
86 
87 public:
88  using result_type = ReturnType;
89 
90  visitor_t(Fns&& ...fns)
91  : impl_(std::forward<Fns>(fns)...)
92  {}
93 
94 template<typename T, typename U=ReturnType>
95  auto operator() (T&& x)
97  !std::is_void<decltype(impl_(std::forward<T>(x)))>{} ||
98  std::is_void<U>{},
99  ReturnType>
100  {
101  return impl_(std::forward<T>(x));
102  }
103 
104  template<typename T, typename U=ReturnType>
105  auto operator() (T&& x)
107  std::is_void<decltype(impl_(std::forward<T>(x)))>{} &&
108  !std::is_void<U>{},
109  ReturnType>
110  {
111  return impl_(std::forward<T>(x)), meta::from_void{};
112  }
113 };
114 
119 template <typename Fn, typename ReturnType=void>
121 {
122  using result_type = ReturnType;
123 
124  otherwise_t(Fn&& fn)
125  : impl_(std::forward<Fn>(fn))
126  {}
127 
128  template <typename ...Args>
129  result_type operator() (Args&& ...args)
130  {
131  return impl_(std::forward<Args>(args)...);
132  }
133 
134 private:
135  Fn impl_;
136 };
137 
138 namespace detail {
139 
140 template<typename ReturnT>
141 struct default_construct
142 {
143  template <typename ...Args>
144  ReturnT operator() (Args&& ...)
145  {
146  return ReturnT();
147  }
148 };
149 
150 } // namespace detail
151 
152 template <typename ReturnType = void,
153  typename Fn = detail::default_construct<ReturnType>>
154 otherwise_t<Fn, ReturnType>
155 otherwise(Fn&& fn = Fn())
156 {
157  return { std::forward<Fn>(fn) };
158 }
159 
164 template <typename Fn, typename ...Args>
165 struct when_t
166 {
167  using result_type = typename std::result_of<Fn(Args...)>::type;
168 
169  when_t(Fn&& fn)
170  : impl_(std::forward<Fn>(fn))
171  {}
172 
173  result_type operator() (Args&& ...args)
174  {
175  return impl_(std::forward<Args>(args)...);
176  }
177 
178 private:
179  Fn impl_;
180 };
181 
187 template <typename ...Args, typename Fn>
188 when_t<Fn,
189  typename boost::mpl::if_<std::is_reference<Args>,
190  Args, const Args&>::type...>
191 when(Fn&& fn)
192 {
193  return { std::forward<Fn>(fn) };
194 }
195 
196 namespace detail {
197 
198 template <typename AccT, typename FnT, typename T,
199  typename Enable = void>
200 struct add_result_of_aux
201 {
202  using type = AccT;
203 };
204 
205 template <typename AccT, typename FnT, typename T>
206 struct add_result_of_aux<AccT, FnT, T,
207  estd::void_t<estd::result_of_t<FnT(T)> > >
208  : boost::mpl::push_back<AccT, estd::result_of_t<FnT(T)> >
209 {};
210 
211 template <typename AccT, typename FnT, typename Ts>
212 struct add_results_of;
213 
214 template <typename AccT, typename FnT, typename T, typename... Ts>
215 struct add_results_of<AccT, FnT, meta::pack<T, Ts...> >
216  : add_results_of<meta::eval_t<add_result_of_aux<AccT, FnT, T> >,
217  FnT,
218  meta::pack<Ts...> >
219 {};
220 
221 template <typename AccT, typename FnT>
222 struct add_results_of<AccT, FnT, meta::pack<> >
223 {
224  using type = AccT;
225 };
226 
227 } // namespace detail
228 
229 template <typename FnT, typename... VariantTs>
231  : meta::unpack<
232  meta::common_type,
233  typename detail::add_results_of<meta::pack<>,
234  FnT,
235  meta::pack<VariantTs...> >::type >
236 {};
237 
238 template <typename FnT, typename... VariantTs>
239 struct visitor_result_of<FnT, meta::pack<VariantTs...> >
240  : visitor_result_of<FnT, VariantTs...>
241 {};
242 
243 template <typename FnT, typename... VariantTs>
244 using visitor_result_of_t = typename visitor_result_of<FnT, VariantTs...>::type;
245 
252 template <typename... FnTs>
253 auto visitor(FnTs&& ...fns)
254  -> visitor_t<
256  typename std::result_of<FnTs(meta::bottom)>::type...>,
257  FnTs...>
258 {
259  return { std::forward<FnTs>(fns)... };
260 }
261 
262 template <typename FnT>
263 auto visitor(FnT&& fn) -> FnT&&
264 {
265  return std::forward<FnT>(fn);
266 }
267 
273 template <typename VariantT, typename... FnTs>
274 auto visitor_for(FnTs&&... fns)
275  -> visitor_t<
276  visitor_result_of_t<
277  detail::visitor_impl<FnTs...>,
278  variant_types_t<VariantT> >,
279  FnTs...>
280 {
281  return { std::forward<FnTs>(fns)... };
282 }
283 
284 template <typename VarianT, typename FnT>
285 auto visitor_for(FnT&& fn) -> FnT&&
286 {
287  return std::forward<FnT>(fn);
288 }
289 
290 } // namespace variant
291 } // namespace atria
typename detail::make_void< Ts... >::type void_t
Similar to C++17 std::void_t.
Definition: type_traits.hpp:48
typename std::enable_if< X, T >::type enable_if_t
Similar to C++14 std::enable_if_t.
Definition: type_traits.hpp:84
STL namespace.
typename common_type< Ts... >::type common_type_t
C++14 style alias for common_type
Wraps a functor such that it has a fixed return value.
Definition: visitor.hpp:120
Type to enable making a type convertible from void.
Definition: utils.hpp:63
Wraps a functor such that it has a fixed argument list.
Definition: visitor.hpp:165
auto visitor_for(FnTs &&...fns) -> visitor_t< visitor_result_of_t< detail::visitor_impl< FnTs... >, variant_types_t< VariantT > >, FnTs... >
Like visitor, but it uses the variant_types in VariantT to deduce what the return type of the visitor...
Definition: visitor.hpp:274
typename detail::unpack< MF, T >::type unpack
Metafunction that given a variadic template MF and a type ArgT, returns MF, or if ArgT is of th...
Definition: pack.hpp:101
auto visitor(FnTs &&...fns) -> visitor_t< meta::common_type_t< typename std::result_of< FnTs(meta::bottom)>::type... >, FnTs... >
Returns a visitor object that can be used to deconstruct various variant types, created by composing ...
Definition: visitor.hpp:253
General visitor based on a set of function objects.
Definition: visitor.hpp:83
C++ amazing templates and reusable implementations awesomeness.
Definition: _doc.hpp:35
when_t< Fn, typename boost::mpl::if_< std::is_reference< Args >, Args, const Args & >::type... > when(Fn &&fn)
Factory for when functors.
Definition: visitor.hpp:191
Fork me on GitHub