• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2015 Paul Fultz II
3     apply.h
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 
8 #ifndef BOOST_HOF_GUARD_APPLY_H
9 #define BOOST_HOF_GUARD_APPLY_H
10 
11 /// apply
12 /// =====
13 ///
14 /// Description
15 /// -----------
16 ///
17 /// The `apply` function calls the function given to it with its arguments.
18 ///
19 /// Synopsis
20 /// --------
21 ///
22 ///     template<class F, class... Ts>
23 ///     constexpr auto apply(F&& f, Ts&&... xs);
24 ///
25 /// Semantics
26 /// ---------
27 ///
28 ///     assert(apply(f)(xs...) == f(xs...));
29 ///     assert(fold(apply, f)(x, y, z) == f(x)(y)(z));
30 ///
31 /// Requirements
32 /// ------------
33 ///
34 /// F must be:
35 ///
36 /// * [Invocable](Invocable)
37 ///
38 /// Example
39 /// -------
40 ///
41 ///     #include <boost/hof.hpp>
42 ///     #include <cassert>
43 ///
44 ///     struct sum_f
45 ///     {
46 ///         template<class T, class U>
47 ///         T operator()(T x, U y) const
48 ///         {
49 ///             return x+y;
50 ///         }
51 ///     };
52 ///
53 ///     int main() {
54 ///         assert(boost::hof::apply(sum_f(), 1, 2) == 3);
55 ///     }
56 ///
57 
58 #include <boost/hof/detail/result_of.hpp>
59 #include <boost/hof/detail/forward.hpp>
60 #include <boost/hof/detail/static_const_var.hpp>
61 
62 #ifdef _MSC_VER
63 #pragma warning(push)
64 #pragma warning(disable: 4003)
65 #endif
66 
67 #define BOOST_HOF_DETAIL_FOREACH_QUAL(m, data) \
68     m(, data) \
69     m(const, data) \
70     m(volatile, data) \
71     m(const volatile, data)
72 
73 namespace boost { namespace hof {
74 
75 namespace detail {
76 #if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE
77 struct apply_mem_fn
78 {
79     template<class...>
80     struct convertible_args;
81 
82     template<class T, class U, class=void>
83     struct is_convertible_args
84     : std::false_type
85     {};
86 
87     template<class... Ts, class... Us>
88     struct is_convertible_args<
89         convertible_args<Ts...>,
90         convertible_args<Us...>,
91         typename std::enable_if<(
92             sizeof...(Ts) == sizeof...(Us)
93         )>::type
94     >
95     : and_<std::is_convertible<Ts, Us>...>
96     {};
97 
98     template<class From, class To>
99     struct is_compatible
100     : std::is_convertible<
101         typename std::add_pointer<typename std::remove_reference<From>::type>::type,
102         typename std::add_pointer<typename std::remove_reference<To>::type>::type
103     >
104     {};
105 
106 #define BOOST_HOF_APPLY_MEM_FN_CALL(cv, data) \
107     template <class R, class Base, class Derived, class... Ts, class... Us, class=typename std::enable_if<and_< \
108         is_compatible<Derived, cv Base>, \
109         is_convertible_args<convertible_args<Us...>, convertible_args<Ts...>> \
110     >::value>::type> \
111     constexpr R operator()(R (Base::*mf)(Ts...) cv, Derived&& ref, Us &&... xs) const \
112     BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...)) \
113     { \
114         return (BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...); \
115     }
116     BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_FN_CALL, ~)
117 };
118 
119 struct apply_mem_data
120 {
121     template<class T, class R>
122     struct match_qualifier
123     { typedef R type; };
124 
125 #define BOOST_HOF_APPLY_MEM_DATA_MATCH(cv, ref) \
126     template<class T, class R> \
127     struct match_qualifier<cv T ref, R> \
128     : match_qualifier<T, cv R ref> \
129     {};
130 
131     BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&)
132     BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&&)
133 
134     template <class Base, class R, class Derived, class=typename std::enable_if<(
135         std::is_base_of<Base, typename std::decay<Derived>::type>::value
136     )>::type>
137     constexpr typename match_qualifier<Derived, R>::type
operator ()boost::hof::detail::apply_mem_data138     operator()(R Base::*pmd, Derived&& ref) const noexcept
139     {
140         return BOOST_HOF_FORWARD(Derived)(ref).*pmd;
141     }
142 };
143 
144 template<class T, class U=decltype(*std::declval<T>())>
145 struct apply_deref
146 { typedef U type; };
147 
148 #endif
149 
150 struct apply_f
151 {
152 #if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE
153     template<class F, class T, class... Ts, class=typename std::enable_if<(
154         std::is_member_function_pointer<typename std::decay<F>::type>::value
155     )>::type>
156     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T>, id_<Ts>...)
157     operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
158     (
159         apply_mem_fn()(f, BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...)
160     );
161 
162     template<class F, class T, class... Ts, class U=typename apply_deref<T>::type, class=typename std::enable_if<(
163         std::is_member_function_pointer<typename std::decay<F>::type>::value
164     )>::type>
165     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<U>, id_<Ts>...)
166     operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
167     (
168         apply_mem_fn()(f, *BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...)
169     );
170 
171     template<class F, class T, class... Ts, class=typename std::enable_if<(
172         std::is_member_function_pointer<typename std::decay<F>::type>::value
173     )>::type>
174     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T&>, id_<Ts>...)
175     operator()(F&& f, const std::reference_wrapper<T>& ref, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
176     (
177         apply_mem_fn()(f, ref.get(), BOOST_HOF_FORWARD(Ts)(xs)...)
178     );
179 
180     template<class F, class T, class=typename std::enable_if<(
181         std::is_member_object_pointer<typename std::decay<F>::type>::value
182     )>::type>
183     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T>)
184     operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS
185     (
186         apply_mem_data()(f, BOOST_HOF_FORWARD(T)(obj))
187     );
188 
189     template<class F, class T, class U=typename apply_deref<T>::type, class=typename std::enable_if<(
190         std::is_member_object_pointer<typename std::decay<F>::type>::value
191     )>::type>
192     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<U>)
193     operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS
194     (
195         apply_mem_data()(f, *BOOST_HOF_FORWARD(T)(obj))
196     );
197 
198     template<class F, class T, class=typename std::enable_if<(
199         std::is_member_object_pointer<typename std::decay<F>::type>::value
200     )>::type>
201     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T&>)
202     operator()(F&& f, const std::reference_wrapper<T>& ref) const BOOST_HOF_SFINAE_MANUAL_RETURNS
203     (
204         apply_mem_data()(f, ref.get())
205     );
206 
207 #else
208 
209     template <class Base, class T, class Derived>
210     constexpr auto operator()(T Base::*pmd, Derived&& ref) const
211     BOOST_HOF_RETURNS(BOOST_HOF_FORWARD(Derived)(ref).*pmd);
212 
213     template <class PMD, class Pointer>
214     constexpr auto operator()(PMD&& pmd, Pointer&& ptr) const
215     BOOST_HOF_RETURNS((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMD)(pmd));
216 
217     template <class Base, class T, class Derived>
218     constexpr auto operator()(T Base::*pmd, const std::reference_wrapper<Derived>& ref) const
219     BOOST_HOF_RETURNS(ref.get().*pmd);
220 
221     template <class Base, class T, class Derived, class... Args>
222     constexpr auto operator()(T Base::*pmf, Derived&& ref, Args&&... args) const
223     BOOST_HOF_RETURNS((BOOST_HOF_FORWARD(Derived)(ref).*pmf)(BOOST_HOF_FORWARD(Args)(args)...));
224 
225     template <class PMF, class Pointer, class... Args>
226     constexpr auto operator()(PMF&& pmf, Pointer&& ptr, Args&&... args) const
227     BOOST_HOF_RETURNS(((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMF)(pmf))(BOOST_HOF_FORWARD(Args)(args)...));
228 
229     template <class Base, class T, class Derived, class... Args>
230     constexpr auto operator()(T Base::*pmf, const std::reference_wrapper<Derived>& ref, Args&&... args) const
231     BOOST_HOF_RETURNS((ref.get().*pmf)(BOOST_HOF_FORWARD(Args)(args)...));
232 
233 #endif
234     template<class F, class... Ts>
235     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(F, id_<Ts>...)
236     operator()(F&& f, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
237     (
238         f(BOOST_HOF_FORWARD(Ts)(xs)...)
239     );
240 };
241 
242 }
243 
244 BOOST_HOF_DECLARE_STATIC_VAR(apply, detail::apply_f);
245 
246 }} // namespace boost::hof
247 
248 #ifdef _MSC_VER
249 #pragma warning(pop)
250 #endif
251 
252 #endif
253