1 | #ifndef BOOST_MP11_UTILITY_HPP_INCLUDED |
2 | #define BOOST_MP11_UTILITY_HPP_INCLUDED |
3 | |
4 | // Copyright 2015-2020 Peter Dimov. |
5 | // |
6 | // Distributed under the Boost Software License, Version 1.0. |
7 | // |
8 | // See accompanying file LICENSE_1_0.txt or copy at |
9 | // http://www.boost.org/LICENSE_1_0.txt |
10 | |
11 | #include <boost/mp11/integral.hpp> |
12 | #include <boost/mp11/detail/mp_list.hpp> |
13 | #include <boost/mp11/detail/mp_fold.hpp> |
14 | #include <boost/mp11/detail/config.hpp> |
15 | |
16 | namespace boost |
17 | { |
18 | namespace mp11 |
19 | { |
20 | |
21 | // mp_identity |
22 | template<class T> struct mp_identity |
23 | { |
24 | using type = T; |
25 | }; |
26 | |
27 | // mp_identity_t |
28 | template<class T> using mp_identity_t = typename mp_identity<T>::type; |
29 | |
30 | // mp_inherit |
31 | template<class... T> struct mp_inherit: T... {}; |
32 | |
33 | // mp_if, mp_if_c |
34 | namespace detail |
35 | { |
36 | |
37 | template<bool C, class T, class... E> struct mp_if_c_impl |
38 | { |
39 | }; |
40 | |
41 | template<class T, class... E> struct mp_if_c_impl<true, T, E...> |
42 | { |
43 | using type = T; |
44 | }; |
45 | |
46 | template<class T, class E> struct mp_if_c_impl<false, T, E> |
47 | { |
48 | using type = E; |
49 | }; |
50 | |
51 | } // namespace detail |
52 | |
53 | template<bool C, class T, class... E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type; |
54 | template<class C, class T, class... E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type; |
55 | |
56 | // mp_valid |
57 | |
58 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_INTEL, != 0 ) // tested at 1800 |
59 | |
60 | // contributed by Roland Schulz in https://github.com/boostorg/mp11/issues/17 |
61 | |
62 | namespace detail |
63 | { |
64 | |
65 | template<class...> using void_t = void; |
66 | |
67 | template<class, template<class...> class F, class... T> |
68 | struct mp_valid_impl: mp_false {}; |
69 | |
70 | template<template<class...> class F, class... T> |
71 | struct mp_valid_impl<void_t<F<T...>>, F, T...>: mp_true {}; |
72 | |
73 | } // namespace detail |
74 | |
75 | template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<void, F, T...>; |
76 | |
77 | #else |
78 | |
79 | // implementation by Bruno Dutra (by the name is_evaluable) |
80 | namespace detail |
81 | { |
82 | |
83 | template<template<class...> class F, class... T> struct mp_valid_impl |
84 | { |
85 | template<template<class...> class G, class = G<T...>> static mp_true check(int); |
86 | template<template<class...> class> static mp_false check(...); |
87 | |
88 | using type = decltype(check<F>(0)); |
89 | }; |
90 | |
91 | } // namespace detail |
92 | |
93 | template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<F, T...>::type; |
94 | |
95 | #endif |
96 | |
97 | template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>; |
98 | |
99 | // mp_defer |
100 | namespace detail |
101 | { |
102 | |
103 | template<template<class...> class F, class... T> struct mp_defer_impl |
104 | { |
105 | using type = F<T...>; |
106 | }; |
107 | |
108 | struct mp_no_type |
109 | { |
110 | }; |
111 | |
112 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) |
113 | |
114 | template<template<class...> class F, class... T> struct mp_defer_cuda_workaround |
115 | { |
116 | using type = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>; |
117 | }; |
118 | |
119 | #endif |
120 | |
121 | } // namespace detail |
122 | |
123 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) |
124 | |
125 | template<template<class...> class F, class... T> using mp_defer = typename detail::mp_defer_cuda_workaround< F, T...>::type; |
126 | |
127 | #else |
128 | |
129 | template<template<class...> class F, class... T> using mp_defer = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>; |
130 | |
131 | #endif |
132 | |
133 | // mp_eval_if, mp_eval_if_c |
134 | namespace detail |
135 | { |
136 | |
137 | template<bool C, class T, template<class...> class F, class... U> struct mp_eval_if_c_impl; |
138 | |
139 | template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<true, T, F, U...> |
140 | { |
141 | using type = T; |
142 | }; |
143 | |
144 | template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<false, T, F, U...>: mp_defer<F, U...> |
145 | { |
146 | }; |
147 | |
148 | } // namespace detail |
149 | |
150 | template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl<C, T, F, U...>::type; |
151 | template<class C, class T, template<class...> class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, F, U...>::type; |
152 | template<class C, class T, class Q, class... U> using mp_eval_if_q = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, Q::template fn, U...>::type; |
153 | |
154 | // mp_eval_if_not |
155 | template<class C, class T, template<class...> class F, class... U> using mp_eval_if_not = mp_eval_if<mp_not<C>, T, F, U...>; |
156 | template<class C, class T, class Q, class... U> using mp_eval_if_not_q = mp_eval_if<mp_not<C>, T, Q::template fn, U...>; |
157 | |
158 | // mp_eval_or |
159 | template<class T, template<class...> class F, class... U> using mp_eval_or = mp_eval_if_not<mp_valid<F, U...>, T, F, U...>; |
160 | template<class T, class Q, class... U> using mp_eval_or_q = mp_eval_or<T, Q::template fn, U...>; |
161 | |
162 | // mp_cond |
163 | |
164 | // so elegant; so doesn't work |
165 | // template<class C, class T, class... E> using mp_cond = mp_eval_if<C, T, mp_cond, E...>; |
166 | |
167 | namespace detail |
168 | { |
169 | |
170 | template<class C, class T, class... E> struct mp_cond_impl; |
171 | |
172 | } // namespace detail |
173 | |
174 | template<class C, class T, class... E> using mp_cond = typename detail::mp_cond_impl<C, T, E...>::type; |
175 | |
176 | namespace detail |
177 | { |
178 | |
179 | template<class C, class T, class... E> using mp_cond_ = mp_eval_if<C, T, mp_cond, E...>; |
180 | |
181 | template<class C, class T, class... E> struct mp_cond_impl: mp_defer<mp_cond_, C, T, E...> |
182 | { |
183 | }; |
184 | |
185 | } // namespace detail |
186 | |
187 | // mp_quote |
188 | template<template<class...> class F> struct mp_quote |
189 | { |
190 | // the indirection through mp_defer works around the language inability |
191 | // to expand T... into a fixed parameter list of an alias template |
192 | |
193 | template<class... T> using fn = typename mp_defer<F, T...>::type; |
194 | }; |
195 | |
196 | // mp_quote_trait |
197 | template<template<class...> class F> struct mp_quote_trait |
198 | { |
199 | template<class... T> using fn = typename F<T...>::type; |
200 | }; |
201 | |
202 | // mp_invoke_q |
203 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) |
204 | |
205 | namespace detail |
206 | { |
207 | |
208 | template<class Q, class... T> struct mp_invoke_q_impl: mp_defer<Q::template fn, T...> {}; |
209 | |
210 | } // namespace detail |
211 | |
212 | template<class Q, class... T> using mp_invoke_q = typename detail::mp_invoke_q_impl<Q, T...>::type; |
213 | |
214 | #elif BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 50000 ) |
215 | |
216 | template<class Q, class... T> using mp_invoke_q = typename mp_defer<Q::template fn, T...>::type; |
217 | |
218 | #else |
219 | |
220 | template<class Q, class... T> using mp_invoke_q = typename Q::template fn<T...>; |
221 | |
222 | #endif |
223 | |
224 | // old name for mp_invoke_q retained for compatibility, but deprecated |
225 | #if !defined(__clang__) |
226 | |
227 | template<class Q, class... T> using mp_invoke BOOST_MP11_DEPRECATED("please use mp_invoke_q" ) = mp_invoke_q<Q, T...>; |
228 | |
229 | #else |
230 | |
231 | // Clang doesn't warn on deprecated alias templates |
232 | |
233 | template<class Q, class... T> struct BOOST_MP11_DEPRECATED("please use mp_invoke_q" ) mp_invoke_ |
234 | { |
235 | using type = mp_invoke_q<Q, T...>; |
236 | }; |
237 | |
238 | template<class Q, class... T> using mp_invoke = typename mp_invoke_<Q, T...>::type; |
239 | |
240 | #endif |
241 | |
242 | // mp_not_fn<P> |
243 | template<template<class...> class P> struct mp_not_fn |
244 | { |
245 | template<class... T> using fn = mp_not< mp_invoke_q<mp_quote<P>, T...> >; |
246 | }; |
247 | |
248 | template<class Q> using mp_not_fn_q = mp_not_fn<Q::template fn>; |
249 | |
250 | // mp_compose |
251 | namespace detail |
252 | { |
253 | |
254 | template<class T, class Q> using mp_reverse_invoke_q = mp_invoke_q<Q, T>; |
255 | |
256 | } // namespace detail |
257 | |
258 | #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) |
259 | |
260 | template<template<class...> class... F> struct mp_compose |
261 | { |
262 | template<class T> using fn = mp_fold<mp_list<mp_quote<F>...>, T, detail::mp_reverse_invoke_q>; |
263 | }; |
264 | |
265 | #endif |
266 | |
267 | template<class... Q> struct mp_compose_q |
268 | { |
269 | template<class T> using fn = mp_fold<mp_list<Q...>, T, detail::mp_reverse_invoke_q>; |
270 | }; |
271 | |
272 | } // namespace mp11 |
273 | } // namespace boost |
274 | |
275 | #endif // #ifndef BOOST_MP11_UTILITY_HPP_INCLUDED |
276 | |