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