• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2016-2018 T. Zachary Laine
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_YAP_USER_MACROS_HPP_INCLUDED
7 #define BOOST_YAP_USER_MACROS_HPP_INCLUDED
8 
9 #include <boost/preprocessor/cat.hpp>
10 #include <boost/preprocessor/repetition/enum_params.hpp>
11 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
12 #include <boost/preprocessor/repetition/enum.hpp>
13 
14 
15 #ifndef BOOST_YAP_DOXYGEN
16 
17 // unary
18 #define BOOST_YAP_OPERATOR_unary_plus(...) +(__VA_ARGS__)
19 #define BOOST_YAP_OPERATOR_negate(...) -(__VA_ARGS__)
20 #define BOOST_YAP_OPERATOR_dereference(...) *(__VA_ARGS__)
21 #define BOOST_YAP_OPERATOR_complement(...) ~(__VA_ARGS__)
22 #define BOOST_YAP_OPERATOR_address_of(...) &(__VA_ARGS__)
23 #define BOOST_YAP_OPERATOR_logical_not(...) !(__VA_ARGS__)
24 #define BOOST_YAP_OPERATOR_pre_inc(...) ++(__VA_ARGS__)
25 #define BOOST_YAP_OPERATOR_pre_dec(...) --(__VA_ARGS__)
26 #define BOOST_YAP_OPERATOR_post_inc(...) ++(__VA_ARGS__, int)
27 #define BOOST_YAP_OPERATOR_post_dec(...) --(__VA_ARGS__, int)
28 
29 // binary
30 #define BOOST_YAP_OPERATOR_shift_left(...) <<(__VA_ARGS__)
31 #define BOOST_YAP_OPERATOR_shift_right(...) >>(__VA_ARGS__)
32 #define BOOST_YAP_OPERATOR_multiplies(...) *(__VA_ARGS__)
33 #define BOOST_YAP_OPERATOR_divides(...) /(__VA_ARGS__)
34 #define BOOST_YAP_OPERATOR_modulus(...) %(__VA_ARGS__)
35 #define BOOST_YAP_OPERATOR_plus(...) +(__VA_ARGS__)
36 #define BOOST_YAP_OPERATOR_minus(...) -(__VA_ARGS__)
37 #define BOOST_YAP_OPERATOR_less(...) <(__VA_ARGS__)
38 #define BOOST_YAP_OPERATOR_greater(...) >(__VA_ARGS__)
39 #define BOOST_YAP_OPERATOR_less_equal(...) <=(__VA_ARGS__)
40 #define BOOST_YAP_OPERATOR_greater_equal(...) >=(__VA_ARGS__)
41 #define BOOST_YAP_OPERATOR_equal_to(...) ==(__VA_ARGS__)
42 #define BOOST_YAP_OPERATOR_not_equal_to(...) !=(__VA_ARGS__)
43 #define BOOST_YAP_OPERATOR_logical_or(...) ||(__VA_ARGS__)
44 #define BOOST_YAP_OPERATOR_logical_and(...) &&(__VA_ARGS__)
45 #define BOOST_YAP_OPERATOR_bitwise_and(...) &(__VA_ARGS__)
46 #define BOOST_YAP_OPERATOR_bitwise_or(...) |(__VA_ARGS__)
47 #define BOOST_YAP_OPERATOR_bitwise_xor(...) ^(__VA_ARGS__)
48 #define BOOST_YAP_OPERATOR_comma(...) ,(__VA_ARGS__)
49 #define BOOST_YAP_OPERATOR_mem_ptr(...) ->*(__VA_ARGS__)
50 #define BOOST_YAP_OPERATOR_assign(...) =(__VA_ARGS__)
51 #define BOOST_YAP_OPERATOR_shift_left_assign(...) <<=(__VA_ARGS__)
52 #define BOOST_YAP_OPERATOR_shift_right_assign(...) >>=(__VA_ARGS__)
53 #define BOOST_YAP_OPERATOR_multiplies_assign(...) *=(__VA_ARGS__)
54 #define BOOST_YAP_OPERATOR_divides_assign(...) /=(__VA_ARGS__)
55 #define BOOST_YAP_OPERATOR_modulus_assign(...) %=(__VA_ARGS__)
56 #define BOOST_YAP_OPERATOR_plus_assign(...) +=(__VA_ARGS__)
57 #define BOOST_YAP_OPERATOR_minus_assign(...) -=(__VA_ARGS__)
58 #define BOOST_YAP_OPERATOR_bitwise_and_assign(...) &=(__VA_ARGS__)
59 #define BOOST_YAP_OPERATOR_bitwise_or_assign(...) |=(__VA_ARGS__)
60 #define BOOST_YAP_OPERATOR_bitwise_xor_assign(...) ^=(__VA_ARGS__)
61 #define BOOST_YAP_OPERATOR_subscript(...) [](__VA_ARGS__)
62 
63 #define BOOST_YAP_INDIRECT_CALL(macro) BOOST_PP_CAT(BOOST_YAP_OPERATOR_, macro)
64 
65 #endif // BOOST_YAP_DOXYGEN
66 
67 
68 /** Defines operator overloads for unary operator \a op_name that each take an
69     expression instantiated from \a expr_template and return an expression
70     instantiated from the \a result_expr_template expression template.  One
71     overload is defined for each of the qualifiers <code>const &</code>,
72     <code>&</code>, and <code>&&</code>.  For the lvalue reference overloads,
73     the argument is captured by reference into the resulting expression.  For
74     the rvalue reference overload, the argument is moved into the resulting
75     expression.
76 
77     Example:
78     \snippet user_macros_snippets.cpp USER_UNARY_OPERATOR
79 
80     \param op_name The operator to be overloaded; this must be one of the \b
81     unary enumerators in <code>expr_kind</code>, without the
82     <code>expr_kind::</code> qualification.
83 
84     \param expr_template The expression template to which the overloads apply.
85     \a expr_template must be an \ref ExpressionTemplate.
86 
87     \param result_expr_template The expression template to use to instantiate
88     the result expression.  \a result_expr_template must be an \ref
89     ExpressionTemplate.
90 */
91 #define BOOST_YAP_USER_UNARY_OPERATOR(                                         \
92     op_name, expr_template, result_expr_template)                              \
93     template<::boost::yap::expr_kind Kind, typename Tuple>                     \
94     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
95         expr_template<Kind, Tuple> const & x)                                  \
96     {                                                                          \
97         using lhs_type = ::boost::yap::detail::operand_type_t<                 \
98             result_expr_template,                                              \
99             expr_template<Kind, Tuple> const &>;                               \
100         using tuple_type = ::boost::hana::tuple<lhs_type>;                     \
101         return result_expr_template<                                           \
102             ::boost::yap::expr_kind::op_name,                                  \
103             tuple_type>{                                                       \
104             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(x)}};    \
105     }                                                                          \
106     template<::boost::yap::expr_kind Kind, typename Tuple>                     \
107     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
108         expr_template<Kind, Tuple> & x)                                        \
109     {                                                                          \
110         using lhs_type = ::boost::yap::detail::operand_type_t<                 \
111             result_expr_template,                                              \
112             expr_template<Kind, Tuple> &>;                                     \
113         using tuple_type = ::boost::hana::tuple<lhs_type>;                     \
114         return result_expr_template<                                           \
115             ::boost::yap::expr_kind::op_name,                                  \
116             tuple_type>{                                                       \
117             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(x)}};    \
118     }                                                                          \
119     template<::boost::yap::expr_kind Kind, typename Tuple>                     \
120     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
121         expr_template<Kind, Tuple> && x)                                       \
122     {                                                                          \
123         using tuple_type = ::boost::hana::tuple<expr_template<Kind, Tuple>>;   \
124         return result_expr_template<                                           \
125             ::boost::yap::expr_kind::op_name,                                  \
126             tuple_type>{tuple_type{std::move(x)}};                             \
127     }
128 
129 
130 /** Defines operator overloads for binary operator \a op_name that each
131     produce an expression instantiated from the \a expr_template expression
132     template.  One overload is defined for each of the qualifiers <code>const
133     &</code>, <code>&</code>, and <code>&&</code>.  For the lvalue reference
134     overloads, <code>*this</code> is captured by reference into the resulting
135     expression.  For the rvalue reference overload, <code>*this</code> is
136     moved into the resulting expression.
137 
138     Note that this does not work for yap::expr_kinds assign, subscript, or
139     call.  Use BOOST_YAP_USER_ASSIGN_OPERATOR,
140     BOOST_YAP_USER_SUBSCRIPT_OPERATOR, or BOOST_YAP_USER_CALL_OPERATOR for
141     those, respectively.
142 
143     Example:
144     \snippet user_macros_snippets.cpp USER_BINARY_OPERATOR
145 
146     \param op_name The operator to be overloaded; this must be one of the \b
147     binary enumerators in <code>expr_kind</code>, except assign, subscript, or
148     call, without the <code>expr_kind::</code> qualification.
149 
150     \param expr_template The expression template to which the overloads apply.
151     \a expr_template must be an \ref ExpressionTemplate.
152 
153     \param result_expr_template The expression template to use to instantiate
154     the result expression.  \a result_expr_template must be an \ref
155     ExpressionTemplate.
156 */
157 #define BOOST_YAP_USER_BINARY_OPERATOR(                                        \
158     op_name, expr_template, result_expr_template)                              \
159     template<::boost::yap::expr_kind Kind, typename Tuple, typename Expr>      \
160     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
161         expr_template<Kind, Tuple> const & lhs, Expr && rhs)                   \
162     {                                                                          \
163         using lhs_type = ::boost::yap::detail::operand_type_t<                 \
164             result_expr_template,                                              \
165             expr_template<Kind, Tuple> const &>;                               \
166         using rhs_type =                                                       \
167             ::boost::yap::detail::operand_type_t<result_expr_template, Expr>;  \
168         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
169         return result_expr_template<                                           \
170             ::boost::yap::expr_kind::op_name,                                  \
171             tuple_type>{                                                       \
172             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(lhs),    \
173                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
174                            static_cast<Expr &&>(rhs))}};                       \
175     }                                                                          \
176     template<::boost::yap::expr_kind Kind, typename Tuple, typename Expr>      \
177     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
178         expr_template<Kind, Tuple> & lhs, Expr && rhs)                         \
179     {                                                                          \
180         using lhs_type = ::boost::yap::detail::operand_type_t<                 \
181             result_expr_template,                                              \
182             expr_template<Kind, Tuple> &>;                                     \
183         using rhs_type =                                                       \
184             ::boost::yap::detail::operand_type_t<result_expr_template, Expr>;  \
185         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
186         return result_expr_template<                                           \
187             ::boost::yap::expr_kind::op_name,                                  \
188             tuple_type>{                                                       \
189             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(lhs),    \
190                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
191                            static_cast<Expr &&>(rhs))}};                       \
192     }                                                                          \
193     template<::boost::yap::expr_kind Kind, typename Tuple, typename Expr>      \
194     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
195         expr_template<Kind, Tuple> && lhs, Expr && rhs)                        \
196     {                                                                          \
197         using lhs_type = ::boost::yap::detail::remove_cv_ref_t<                \
198             expr_template<Kind, Tuple> &&>;                                    \
199         using rhs_type =                                                       \
200             ::boost::yap::detail::operand_type_t<result_expr_template, Expr>;  \
201         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
202         return result_expr_template<                                           \
203             ::boost::yap::expr_kind::op_name,                                  \
204             tuple_type>{                                                       \
205             tuple_type{std::move(lhs),                                         \
206                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
207                            static_cast<Expr &&>(rhs))}};                       \
208     }                                                                          \
209     template<typename T, ::boost::yap::expr_kind Kind, typename Tuple>         \
210     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
211         T && lhs, expr_template<Kind, Tuple> && rhs)                           \
212         ->::boost::yap::detail::free_binary_op_result_t<                       \
213             result_expr_template,                                              \
214             ::boost::yap::expr_kind::op_name,                                  \
215             T,                                                                 \
216             expr_template<Kind, Tuple> &&>                                     \
217     {                                                                          \
218         using result_types = ::boost::yap::detail::free_binary_op_result<      \
219             result_expr_template,                                              \
220             ::boost::yap::expr_kind::op_name,                                  \
221             T,                                                                 \
222             expr_template<Kind, Tuple> &&>;                                    \
223         using lhs_type = typename result_types::lhs_type;                      \
224         using rhs_type = typename result_types::rhs_type;                      \
225         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
226         return {tuple_type{lhs_type{static_cast<T &&>(lhs)}, std::move(rhs)}}; \
227     }                                                                          \
228     template<typename T, ::boost::yap::expr_kind Kind, typename Tuple>         \
229     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
230         T && lhs, expr_template<Kind, Tuple> const & rhs)                      \
231         ->::boost::yap::detail::free_binary_op_result_t<                       \
232             result_expr_template,                                              \
233             ::boost::yap::expr_kind::op_name,                                  \
234             T,                                                                 \
235             expr_template<Kind, Tuple> const &>                                \
236     {                                                                          \
237         using result_types = ::boost::yap::detail::free_binary_op_result<      \
238             result_expr_template,                                              \
239             ::boost::yap::expr_kind::op_name,                                  \
240             T,                                                                 \
241             expr_template<Kind, Tuple> const &>;                               \
242         using lhs_type = typename result_types::lhs_type;                      \
243         using rhs_type = typename result_types::rhs_type;                      \
244         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
245         using rhs_tuple_type = typename result_types::rhs_tuple_type;          \
246         return {tuple_type{lhs_type{static_cast<T &&>(lhs)},                   \
247                            rhs_type{rhs_tuple_type{std::addressof(rhs)}}}};    \
248     }                                                                          \
249     template<typename T, ::boost::yap::expr_kind Kind, typename Tuple>         \
250     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(                  \
251         T && lhs, expr_template<Kind, Tuple> & rhs)                            \
252         ->::boost::yap::detail::free_binary_op_result_t<                       \
253             result_expr_template,                                              \
254             ::boost::yap::expr_kind::op_name,                                  \
255             T,                                                                 \
256             expr_template<Kind, Tuple> &>                                      \
257     {                                                                          \
258         using result_types = ::boost::yap::detail::free_binary_op_result<      \
259             result_expr_template,                                              \
260             ::boost::yap::expr_kind::op_name,                                  \
261             T,                                                                 \
262             expr_template<Kind, Tuple> &>;                                     \
263         using lhs_type = typename result_types::lhs_type;                      \
264         using rhs_type = typename result_types::rhs_type;                      \
265         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
266         using rhs_tuple_type = typename result_types::rhs_tuple_type;          \
267         return {tuple_type{lhs_type{static_cast<T &&>(lhs)},                   \
268                            rhs_type{rhs_tuple_type{std::addressof(rhs)}}}};    \
269     }
270 
271 
272 /** Defines operator overloads for \a operator=() that each produce an
273     expression instantiated from the \a expr_template expression template.
274     One overload is defined for each of the qualifiers <code>const &</code>,
275     <code>&</code>, and <code>&&</code>.  For the lvalue reference overloads,
276     <code>*this</code> is captured by reference into the resulting expression.
277     For the rvalue reference overload, <code>*this</code> is moved into the
278     resulting expression.
279 
280     The \a rhs parameter to each of the defined overloads may be any type,
281     including an expression, except that the overloads are constrained by
282     std::enable_if<> not to conflict with the assignment and move assignement
283     operators.  If \a rhs is a non-expression, it is wrapped in a terminal
284     expression.
285 
286     Example:
287     \snippet user_macros_snippets.cpp USER_ASSIGN_OPERATOR
288 
289     \param this_type The type of the class the operator is a member of; this
290     is required to avoid clashing with the assignment and move assignement
291     operators.
292 
293     \param expr_template The expression template to use to instantiate the
294     result expression.  \a expr_template must be an \ref
295     ExpressionTemplate.
296 */
297 #define BOOST_YAP_USER_ASSIGN_OPERATOR(this_type, expr_template)               \
298     template<                                                                  \
299         typename Expr,                                                         \
300         typename = std::enable_if_t<                                           \
301             !::boost::yap::detail::copy_or_move<this_type, Expr &&>::value>>   \
302     constexpr auto operator=(Expr && rhs) const &                              \
303     {                                                                          \
304         using lhs_type = ::boost::yap::detail::                                \
305             operand_type_t<expr_template, this_type const &>;                  \
306         using rhs_type =                                                       \
307             ::boost::yap::detail::operand_type_t<expr_template, Expr>;         \
308         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
309         return expr_template<::boost::yap::expr_kind::assign, tuple_type>{     \
310             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this),  \
311                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
312                            static_cast<Expr &&>(rhs))}};                       \
313     }                                                                          \
314     template<                                                                  \
315         typename Expr,                                                         \
316         typename = std::enable_if_t<                                           \
317             !::boost::yap::detail::copy_or_move<this_type, Expr &&>::value>>   \
318     constexpr auto operator=(Expr && rhs) &                                    \
319     {                                                                          \
320         using lhs_type = ::boost::yap::detail::                                \
321             operand_type_t<expr_template, decltype(*this)>;                    \
322         using rhs_type =                                                       \
323             ::boost::yap::detail::operand_type_t<expr_template, Expr>;         \
324         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
325         return expr_template<::boost::yap::expr_kind::assign, tuple_type>{     \
326             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this),  \
327                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
328                            static_cast<Expr &&>(rhs))}};                       \
329     }                                                                          \
330     template<                                                                  \
331         typename Expr,                                                         \
332         typename = std::enable_if_t<                                           \
333             !::boost::yap::detail::copy_or_move<this_type, Expr &&>::value>>   \
334     constexpr auto operator=(Expr && rhs) &&                                   \
335     {                                                                          \
336         using rhs_type =                                                       \
337             ::boost::yap::detail::operand_type_t<expr_template, Expr>;         \
338         using tuple_type = ::boost::hana::tuple<this_type, rhs_type>;          \
339         return expr_template<::boost::yap::expr_kind::assign, tuple_type>{     \
340             tuple_type{std::move(*this),                                       \
341                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
342                            static_cast<Expr &&>(rhs))}};                       \
343     }
344 
345 
346 /** Defines operator overloads for \a operator[]() that each produce an
347     expression instantiated from the \a expr_template expression template.
348     One overload is defined for each of the qualifiers <code>const &</code>,
349     <code>&</code>, and <code>&&</code>.  For the lvalue reference overloads,
350     <code>*this</code> is captured by reference into the resulting expression.
351     For the rvalue reference overload, <code>*this</code> is moved into the
352     resulting expression.
353 
354     The \a rhs parameter to each of the defined overloads may be any type,
355     including an expression, except that the overloads are constrained by
356     std::enable_if<> not to conflict with the assignment and move assignement
357     operators.  If \a rhs is a non-expression, it is wrapped in a terminal
358     expression.
359 
360     Example:
361     \snippet user_macros_snippets.cpp USER_SUBSCRIPT_OPERATOR
362 
363     \param expr_template The expression template to use to instantiate the
364     result expression.  \a expr_template must be an \ref
365     ExpressionTemplate.
366 */
367 #define BOOST_YAP_USER_SUBSCRIPT_OPERATOR(expr_template)                       \
368     template<typename Expr>                                                    \
369     constexpr auto operator[](Expr && rhs) const &                             \
370     {                                                                          \
371         using lhs_type = ::boost::yap::detail::                                \
372             operand_type_t<expr_template, decltype(*this)>;                    \
373         using rhs_type =                                                       \
374             ::boost::yap::detail::operand_type_t<expr_template, Expr>;         \
375         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
376         return expr_template<::boost::yap::expr_kind::subscript, tuple_type>{  \
377             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this),  \
378                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
379                            static_cast<Expr &&>(rhs))}};                       \
380     }                                                                          \
381     template<typename Expr>                                                    \
382     constexpr auto operator[](Expr && rhs) &                                   \
383     {                                                                          \
384         using lhs_type = ::boost::yap::detail::                                \
385             operand_type_t<expr_template, decltype(*this)>;                    \
386         using rhs_type =                                                       \
387             ::boost::yap::detail::operand_type_t<expr_template, Expr>;         \
388         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
389         return expr_template<::boost::yap::expr_kind::subscript, tuple_type>{  \
390             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this),  \
391                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
392                            static_cast<Expr &&>(rhs))}};                       \
393     }                                                                          \
394     template<typename Expr>                                                    \
395     constexpr auto operator[](Expr && rhs) &&                                  \
396     {                                                                          \
397         using lhs_type =                                                       \
398             ::boost::yap::detail::remove_cv_ref_t<decltype(*this)>;            \
399         using rhs_type =                                                       \
400             ::boost::yap::detail::operand_type_t<expr_template, Expr>;         \
401         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
402         return expr_template<::boost::yap::expr_kind::subscript, tuple_type>{  \
403             tuple_type{std::move(*this),                                       \
404                        ::boost::yap::detail::make_operand<rhs_type>{}(         \
405                            static_cast<Expr &&>(rhs))}};                       \
406     }
407 
408 
409 /** Defines operator overloads for the call operator taking any number of
410     parameters ("operator()") that each produce an expression instantiated
411     from the \a expr_template expression template.  One overload is defined
412     for each of the qualifiers <code>const &</code>, <code>&</code>, and
413     <code>&&</code>.  For the lvalue reference overloads, <code>*this</code>
414     is captured by reference into the resulting expression.  For the rvalue
415     reference overload, <code>*this</code> is moved into the resulting
416     expression.
417 
418     The \a u parameters to each of the defined overloads may be any type,
419     including an expression.  Each non-expression is wrapped in a terminal
420     expression.
421 
422     Example:
423     \snippet user_macros_snippets.cpp USER_CALL_OPERATOR
424 
425     \param expr_template The expression template to use to instantiate the
426     result expression.  \a expr_template must be an \ref
427     ExpressionTemplate.
428 */
429 #define BOOST_YAP_USER_CALL_OPERATOR(expr_template)                            \
430     template<typename... U>                                                    \
431     constexpr auto operator()(U &&... u) const &                               \
432     {                                                                          \
433         using lhs_type = ::boost::yap::detail::                                \
434             operand_type_t<expr_template, decltype(*this)>;                    \
435         using tuple_type = ::boost::hana::tuple<                               \
436             lhs_type,                                                          \
437             ::boost::yap::detail::operand_type_t<expr_template, U>...>;        \
438         return expr_template<::boost::yap::expr_kind::call, tuple_type>{       \
439             tuple_type{                                                        \
440                 ::boost::yap::detail::make_operand<lhs_type>{}(*this),         \
441                 ::boost::yap::detail::make_operand<                            \
442                     ::boost::yap::detail::operand_type_t<expr_template, U>>{}( \
443                     static_cast<U &&>(u))...}};                                \
444     }                                                                          \
445     template<typename... U>                                                    \
446     constexpr auto operator()(U &&... u) &                                     \
447     {                                                                          \
448         using lhs_type = ::boost::yap::detail::                                \
449             operand_type_t<expr_template, decltype(*this)>;                    \
450         using tuple_type = ::boost::hana::tuple<                               \
451             lhs_type,                                                          \
452             ::boost::yap::detail::operand_type_t<expr_template, U>...>;        \
453         return expr_template<::boost::yap::expr_kind::call, tuple_type>{       \
454             tuple_type{                                                        \
455                 ::boost::yap::detail::make_operand<lhs_type>{}(*this),         \
456                 ::boost::yap::detail::make_operand<                            \
457                     ::boost::yap::detail::operand_type_t<expr_template, U>>{}( \
458                     static_cast<U &&>(u))...}};                                \
459     }                                                                          \
460     template<typename... U>                                                    \
461     constexpr auto operator()(U &&... u) &&                                    \
462     {                                                                          \
463         using this_type =                                                      \
464             ::boost::yap::detail::remove_cv_ref_t<decltype(*this)>;            \
465         using tuple_type = ::boost::hana::tuple<                               \
466             this_type,                                                         \
467             ::boost::yap::detail::operand_type_t<expr_template, U>...>;        \
468         return expr_template<::boost::yap::expr_kind::call, tuple_type>{       \
469             tuple_type{                                                        \
470                 std::move(*this),                                              \
471                 ::boost::yap::detail::make_operand<                            \
472                     ::boost::yap::detail::operand_type_t<expr_template, U>>{}( \
473                     static_cast<U &&>(u))...}};                                \
474     }
475 
476 
477 #ifndef BOOST_YAP_DOXYGEN
478 
479 #define BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T(z, n, expr_template)            \
480     ::boost::yap::detail::operand_type_t<expr_template, BOOST_PP_CAT(U, n)>
481 #define BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND(z, n, expr_template)         \
482     ::boost::yap::detail::make_operand<::boost::yap::detail::operand_type_t<   \
483         expr_template,                                                         \
484         BOOST_PP_CAT(U, n)>>{}(                                                \
485         static_cast<BOOST_PP_CAT(U, n) &&>(BOOST_PP_CAT(u, n)))
486 
487 #endif
488 
489 /** Defines operator overloads for the call operator taking N parameters
490     ("operator()(t0, t1, ... tn-1)") that each produce an expression
491     instantiated from the \a expr_template expression template.  One overload
492     is defined for each of the qualifiers <code>const &</code>,
493     <code>&</code>, and <code>&&</code>.  For the lvalue reference overloads,
494     <code>*this</code> is captured by reference into the resulting expression.
495     For the rvalue reference overload, <code>*this</code> is moved into the
496     resulting expression.
497 
498     The \a u parameters to each of the defined overloads may be any type,
499     including an expression.  Each non-expression is wrapped in a terminal
500     expression.
501 
502     Example:
503     \snippet user_macros_snippets.cpp USER_CALL_OPERATOR
504 
505     \param expr_template The expression template to use to instantiate the
506     result expression.  \a expr_template must be an \ref
507     ExpressionTemplate.
508 
509     \param n The number of parameters accepted by the operator() overloads.  n
510     must be <= BOOST_PP_LIMIT_REPEAT.
511 */
512 #define BOOST_YAP_USER_CALL_OPERATOR_N(expr_template, n)                       \
513     template<BOOST_PP_ENUM_PARAMS(n, typename U)>                              \
514     constexpr auto operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, U, &&u)) const &  \
515     {                                                                          \
516         using lhs_type = ::boost::yap::detail::                                \
517             operand_type_t<expr_template, decltype(*this)>;                    \
518         using tuple_type = ::boost::hana::tuple<                               \
519             lhs_type,                                                          \
520             BOOST_PP_ENUM(                                                     \
521                 n, BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T, expr_template)>;    \
522         return expr_template<::boost::yap::expr_kind::call, tuple_type>{       \
523             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this),  \
524                        BOOST_PP_ENUM(                                          \
525                            n,                                                  \
526                            BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND,          \
527                            expr_template)}};                                   \
528     }                                                                          \
529     template<BOOST_PP_ENUM_PARAMS(n, typename U)>                              \
530     constexpr auto operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, U, &&u)) &        \
531     {                                                                          \
532         using lhs_type = ::boost::yap::detail::                                \
533             operand_type_t<expr_template, decltype(*this)>;                    \
534         using tuple_type = ::boost::hana::tuple<                               \
535             lhs_type,                                                          \
536             BOOST_PP_ENUM(                                                     \
537                 n, BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T, expr_template)>;    \
538         return expr_template<::boost::yap::expr_kind::call, tuple_type>{       \
539             tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this),  \
540                        BOOST_PP_ENUM(                                          \
541                            n,                                                  \
542                            BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND,          \
543                            expr_template)}};                                   \
544     }                                                                          \
545     template<BOOST_PP_ENUM_PARAMS(n, typename U)>                              \
546     constexpr auto operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, U, &&u)) &&       \
547     {                                                                          \
548         using this_type =                                                      \
549             ::boost::yap::detail::remove_cv_ref_t<decltype(*this)>;            \
550         using tuple_type = ::boost::hana::tuple<                               \
551             this_type,                                                         \
552             BOOST_PP_ENUM(                                                     \
553                 n, BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T, expr_template)>;    \
554         return expr_template<::boost::yap::expr_kind::call, tuple_type>{       \
555             tuple_type{std::move(*this),                                       \
556                        BOOST_PP_ENUM(                                          \
557                            n,                                                  \
558                            BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND,          \
559                            expr_template)}};                                   \
560     }
561 
562 
563 /** Defines a 3-parameter function <code>if_else()</code> that acts as an
564     analogue to the ternary operator (<code>?:</code>), since the ternary
565     operator is not user-overloadable.  The return type of
566     <code>if_else()</code> is an expression instantiated from the \a
567     expr_template expression template.
568 
569     At least one parameter to <code>if_else()</code> must be an expression.
570 
571     For each parameter E passed to <code>if_else()</code>, if E is an rvalue,
572     E is moved into the result, and otherwise E is captured by reference into
573     the result.
574 
575     Example:
576     \snippet user_macros_snippets.cpp USER_EXPR_IF_ELSE
577 
578     \param expr_template The expression template to use to instantiate the
579     result expression.  \a expr_template must be an \ref
580     ExpressionTemplate.
581 */
582 #define BOOST_YAP_USER_EXPR_IF_ELSE(expr_template)                             \
583     template<typename Expr1, typename Expr2, typename Expr3>                   \
584     constexpr auto if_else(Expr1 && expr1, Expr2 && expr2, Expr3 && expr3)     \
585         ->::boost::yap::detail::                                               \
586             ternary_op_result_t<expr_template, Expr1, Expr2, Expr3>            \
587     {                                                                          \
588         using result_types = ::boost::yap::detail::                            \
589             ternary_op_result<expr_template, Expr1, Expr2, Expr3>;             \
590         using cond_type = typename result_types::cond_type;                    \
591         using then_type = typename result_types::then_type;                    \
592         using else_type = typename result_types::else_type;                    \
593         using tuple_type =                                                     \
594             ::boost::hana::tuple<cond_type, then_type, else_type>;             \
595         return {tuple_type{::boost::yap::detail::make_operand<cond_type>{}(    \
596                                static_cast<Expr1 &&>(expr1)),                  \
597                            ::boost::yap::detail::make_operand<then_type>{}(    \
598                                static_cast<Expr2 &&>(expr2)),                  \
599                            ::boost::yap::detail::make_operand<else_type>{}(    \
600                                static_cast<Expr3 &&>(expr3))}};                \
601     }
602 
603 
604 /** Defines a function <code>if_else()</code> that acts as an analogue to the
605     ternary operator (<code>?:</code>), since the ternary operator is not
606     user-overloadable.  The return type of <code>if_else()</code> is an
607     expression instantiated from the \a expr_template expression template.
608 
609     Each parameter to <code>if_else()</code> may be any type that is \b not an
610     expression.  At least on parameter must be a type <code>T</code> for which
611     \code udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value
612     \endcode is true.  Each parameter is wrapped in a terminal expression.
613 
614     Example:
615     \snippet user_macros_snippets.cpp USER_UDT_ANY_IF_ELSE
616 
617     \param expr_template The expression template to use to instantiate the
618     result expression.  \a expr_template must be an \ref
619     ExpressionTemplate.
620 
621     \param udt_trait A trait template to use to constrain which types are
622     accepted as template parameters to <code>if_else()</code>.
623 */
624 #define BOOST_YAP_USER_UDT_ANY_IF_ELSE(expr_template, udt_trait)               \
625     template<typename Expr1, typename Expr2, typename Expr3>                   \
626     constexpr auto if_else(Expr1 && expr1, Expr2 && expr2, Expr3 && expr3)     \
627         ->::boost::yap::detail::udt_any_ternary_op_result_t<                   \
628             expr_template,                                                     \
629             Expr1,                                                             \
630             Expr2,                                                             \
631             Expr3,                                                             \
632             udt_trait>                                                         \
633     {                                                                          \
634         using result_types = ::boost::yap::detail::udt_any_ternary_op_result<  \
635             expr_template,                                                     \
636             Expr1,                                                             \
637             Expr2,                                                             \
638             Expr3,                                                             \
639             udt_trait>;                                                        \
640         using cond_type = typename result_types::cond_type;                    \
641         using then_type = typename result_types::then_type;                    \
642         using else_type = typename result_types::else_type;                    \
643         using tuple_type =                                                     \
644             ::boost::hana::tuple<cond_type, then_type, else_type>;             \
645         return {tuple_type{::boost::yap::detail::make_operand<cond_type>{}(    \
646                                static_cast<Expr1 &&>(expr1)),                  \
647                            ::boost::yap::detail::make_operand<then_type>{}(    \
648                                static_cast<Expr2 &&>(expr2)),                  \
649                            ::boost::yap::detail::make_operand<else_type>{}(    \
650                                static_cast<Expr3 &&>(expr3))}};                \
651     }
652 
653 
654 /** Defines a free/non-member operator overload for unary operator \a op_name
655     that produces an expression instantiated from the \a expr_template
656     expression template.
657 
658     The parameter to the defined operator overload may be any type that is \b
659     not an expression and for which \code
660     udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value \endcode is
661     true.  The parameter is wrapped in a terminal expression.
662 
663     Example:
664     \snippet user_macros_snippets.cpp USER_UDT_UNARY_OPERATOR
665 
666     \param op_name The operator to be overloaded; this must be one of the \b
667     unary enumerators in <code>expr_kind</code>, without the
668     <code>expr_kind::</code> qualification.
669 
670     \param expr_template The expression template to use to instantiate the
671     result expression.  \a expr_template must be an \ref
672     ExpressionTemplate.
673 
674     \param udt_trait A trait template to use to constrain which types are
675     accepted as template parameters to the defined operator overload.
676 */
677 #define BOOST_YAP_USER_UDT_UNARY_OPERATOR(op_name, expr_template, udt_trait)   \
678     template<typename T>                                                       \
679     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(T && x)           \
680         ->::boost::yap::detail::udt_unary_op_result_t<                         \
681             expr_template,                                                     \
682             ::boost::yap::expr_kind::op_name,                                  \
683             T,                                                                 \
684             udt_trait>                                                         \
685     {                                                                          \
686         using result_types = ::boost::yap::detail::udt_unary_op_result<        \
687             expr_template,                                                     \
688             ::boost::yap::expr_kind::op_name,                                  \
689             T,                                                                 \
690             udt_trait>;                                                        \
691         using x_type = typename result_types::x_type;                          \
692         using tuple_type = ::boost::hana::tuple<x_type>;                       \
693         return {tuple_type{x_type{static_cast<T &&>(x)}}};                     \
694     }
695 
696 
697 /** Defines a free/non-member operator overload for binary operator \a op_name
698     that produces an expression instantiated from the \a expr_template
699     expression template.
700 
701     The \a lhs parameter to the defined operator overload may be any type that
702     is \b not an expression and for which \code
703     t_udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value \endcode is
704     true.  The parameter is wrapped in a terminal expression.
705 
706     The \a rhs parameter to the defined operator overload may be any type that
707     is \b not an expression and for which \code
708     u_udt_trait<std::remove_cv_t<std::remove_reference_t<U>>>::value \endcode is
709     true.  The parameter is wrapped in a terminal expression.
710 
711     Example:
712     \snippet user_macros_snippets.cpp USER_UDT_UDT_BINARY_OPERATOR
713 
714     \param op_name The operator to be overloaded; this must be one of the \b
715     binary enumerators in <code>expr_kind</code>, without the
716     <code>expr_kind::</code> qualification.
717 
718     \param expr_template The expression template to use to instantiate the
719     result expression.  \a expr_template must be an \ref
720     ExpressionTemplate.
721 
722     \param t_udt_trait A trait template to use to constrain which types are
723     accepted as \a T template parameters to the defined operator overload.
724 
725     \param u_udt_trait A trait template to use to constrain which types are
726     accepted as \a U template parameters to the defined operator overload.
727 */
728 #define BOOST_YAP_USER_UDT_UDT_BINARY_OPERATOR(                                \
729     op_name, expr_template, t_udt_trait, u_udt_trait)                          \
730     template<typename T, typename U>                                           \
731     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(T && lhs, U && rhs) \
732         ->::boost::yap::detail::udt_udt_binary_op_result_t<                    \
733             expr_template,                                                     \
734             ::boost::yap::expr_kind::op_name,                                  \
735             T,                                                                 \
736             U,                                                                 \
737             t_udt_trait,                                                       \
738             u_udt_trait>                                                       \
739     {                                                                          \
740         using result_types = ::boost::yap::detail::udt_udt_binary_op_result<   \
741             expr_template,                                                     \
742             ::boost::yap::expr_kind::op_name,                                  \
743             T,                                                                 \
744             U,                                                                 \
745             t_udt_trait,                                                       \
746             u_udt_trait>;                                                      \
747         using lhs_type = typename result_types::lhs_type;                      \
748         using rhs_type = typename result_types::rhs_type;                      \
749         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
750         return {tuple_type{                                                    \
751             lhs_type{static_cast<T &&>(lhs)},                                  \
752             rhs_type{static_cast<U &&>(rhs)},                                  \
753         }};                                                                    \
754     }
755 
756 
757 /** Defines a free/non-member operator overload for binary operator \a op_name
758     that produces an expression instantiated from the \a expr_template
759     expression template.
760 
761     The \a lhs and \a rhs parameters to the defined operator overload may be any
762    types that are \b not expressions.  Each parameter is wrapped in a terminal
763    expression.
764 
765     At least one of the parameters to the defined operator overload must be a
766     type \c T for which \code
767     udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value \endcode is
768     true.
769 
770     Example:
771     \snippet user_macros_snippets.cpp USER_UDT_ANY_BINARY_OPERATOR
772 
773     \param op_name The operator to be overloaded; this must be one of the \b
774     binary enumerators in <code>expr_kind</code>, without the
775     <code>expr_kind::</code> qualification.
776 
777     \param expr_template The expression template to use to instantiate the
778     result expression.  \a expr_template must be an \ref
779     ExpressionTemplate.
780 
781     \param udt_trait A trait template to use to constrain which types are
782     accepted as template parameters to the defined operator overload.
783 */
784 #define BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(                                \
785     op_name, expr_template, udt_trait)                                         \
786     template<typename T, typename U>                                           \
787     constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(T && lhs, U && rhs) \
788         ->::boost::yap::detail::udt_any_binary_op_result_t<                    \
789             expr_template,                                                     \
790             ::boost::yap::expr_kind::op_name,                                  \
791             T,                                                                 \
792             U,                                                                 \
793             udt_trait>                                                         \
794     {                                                                          \
795         using result_types = ::boost::yap::detail::udt_any_binary_op_result<   \
796             expr_template,                                                     \
797             ::boost::yap::expr_kind::op_name,                                  \
798             T,                                                                 \
799             U,                                                                 \
800             udt_trait>;                                                        \
801         using lhs_type = typename result_types::lhs_type;                      \
802         using rhs_type = typename result_types::rhs_type;                      \
803         using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>;           \
804         return {tuple_type{lhs_type{static_cast<T &&>(lhs)},                   \
805                            rhs_type{static_cast<U &&>(rhs)}}};                 \
806     }
807 
808 
809 /** Defines user defined literal template that creates literal placeholders
810     instantiated from the \a expr_template expression template.  It is
811     recommended that you put this in its own namespace.
812 
813     \param expr_template The expression template to use to instantiate the
814     result expression.  \a expr_template must be an \ref
815     ExpressionTemplate.
816 */
817 #define BOOST_YAP_USER_LITERAL_PLACEHOLDER_OPERATOR(expr_template)             \
818     template<char... c>                                                        \
819     constexpr auto operator"" _p()                                             \
820     {                                                                          \
821         using i = ::boost::hana::llong<                                        \
822             ::boost::hana::ic_detail::parse<sizeof...(c)>({c...})>;            \
823         static_assert(1 <= i::value, "Placeholders must be >= 1.");            \
824         return expr_template<                                                  \
825             ::boost::yap::expr_kind::terminal,                                 \
826             ::boost::hana::tuple<::boost::yap::placeholder<i::value>>>{};      \
827     }
828 
829 #endif
830