• 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 #include <boost/yap/expression.hpp>
7 #include <boost/yap/print.hpp>
8 
9 #include <boost/test/minimal.hpp>
10 
11 #include <sstream>
12 #include <regex>
13 
14 
15 template<typename T>
16 using term = boost::yap::terminal<boost::yap::expression, T>;
17 
18 template<typename T>
19 using ref = boost::yap::expression_ref<boost::yap::expression, T>;
20 
21 namespace yap = boost::yap;
22 namespace bh = boost::hana;
23 
24 
25 template<boost::yap::expr_kind Kind, typename Tuple>
26 struct user_expr
27 {
28     static boost::yap::expr_kind const kind = Kind;
29 
30     Tuple elements;
31 };
32 
33 BOOST_YAP_USER_BINARY_OPERATOR(plus, user_expr, user_expr)
34 
35 template<typename T>
36 using user_term = boost::yap::terminal<user_expr, T>;
37 
38 template<typename T>
39 using user_ref = boost::yap::expression_ref<user_expr, T>;
40 
41 struct thing
42 {};
43 
fix_tti(std::string s)44 std::string fix_tti(std::string s)
45 {
46     // msvc: remove struct/class prefixes
47     static const std::regex estruct("(struct|class) ");
48     s = std::regex_replace(s, estruct, "");
49 
50     // gcc/clang: strip integral literals suffixes
51     static const std::regex eint("(\\d)u?l{0,2}");
52     s = std::regex_replace(s, eint, "$1");
53 
54     return s;
55 }
56 
test_main(int,char * [])57 int test_main(int, char * [])
58 {
59     {
60         BOOST_CHECK(
61             yap::op_string(yap::expr_kind::terminal) == std::string("term"));
62         BOOST_CHECK(
63             yap::op_string(yap::expr_kind::unary_plus) == std::string("+"));
64         BOOST_CHECK(yap::op_string(yap::expr_kind::negate) == std::string("-"));
65         BOOST_CHECK(
66             yap::op_string(yap::expr_kind::dereference) == std::string("*"));
67         BOOST_CHECK(
68             yap::op_string(yap::expr_kind::complement) == std::string("~"));
69         BOOST_CHECK(
70             yap::op_string(yap::expr_kind::address_of) == std::string("&"));
71         BOOST_CHECK(
72             yap::op_string(yap::expr_kind::logical_not) == std::string("!"));
73 
74         BOOST_CHECK(yap::op_string(yap::expr_kind::pre_inc) == std::string("++"));
75         BOOST_CHECK(yap::op_string(yap::expr_kind::pre_dec) == std::string("--"));
76         BOOST_CHECK(
77             yap::op_string(yap::expr_kind::post_inc) == std::string("++(int)"));
78         BOOST_CHECK(
79             yap::op_string(yap::expr_kind::post_dec) == std::string("--(int)"));
80 
81         BOOST_CHECK(
82             yap::op_string(yap::expr_kind::shift_left) == std::string("<<"));
83         BOOST_CHECK(
84             yap::op_string(yap::expr_kind::shift_right) == std::string(">>"));
85         BOOST_CHECK(
86             yap::op_string(yap::expr_kind::multiplies) == std::string("*"));
87         BOOST_CHECK(yap::op_string(yap::expr_kind::divides) == std::string("/"));
88         BOOST_CHECK(yap::op_string(yap::expr_kind::modulus) == std::string("%"));
89 
90         BOOST_CHECK(
91             yap::op_string(yap::expr_kind::multiplies_assign) ==
92             std::string("*="));
93         BOOST_CHECK(
94             yap::op_string(yap::expr_kind::divides_assign) ==
95             std::string("/="));
96         BOOST_CHECK(
97             yap::op_string(yap::expr_kind::modulus_assign) ==
98             std::string("%="));
99 
100         BOOST_CHECK(
101             yap::op_string(yap::expr_kind::plus_assign) == std::string("+="));
102         BOOST_CHECK(
103             yap::op_string(yap::expr_kind::minus_assign) == std::string("-="));
104         BOOST_CHECK(
105             yap::op_string(yap::expr_kind::bitwise_and_assign) ==
106             std::string("&="));
107         BOOST_CHECK(
108             yap::op_string(yap::expr_kind::bitwise_or_assign) ==
109             std::string("|="));
110         BOOST_CHECK(
111             yap::op_string(yap::expr_kind::bitwise_xor_assign) ==
112             std::string("^="));
113         BOOST_CHECK(
114             yap::op_string(yap::expr_kind::subscript) == std::string("[]"));
115         BOOST_CHECK(yap::op_string(yap::expr_kind::if_else) == std::string("?:"));
116         BOOST_CHECK(yap::op_string(yap::expr_kind::call) == std::string("()"));
117         BOOST_CHECK(
118             yap::op_string(yap::expr_kind(-1)) ==
119             std::string("** ERROR: UNKNOWN OPERATOR! **"));
120     }
121 
122     {
123         std::ostringstream oss;
124         int i = 0;
125         bh::tuple<int> tuple{i};
126         yap::detail::print_type(oss, tuple);
127         BOOST_CHECK(oss.str() == "int");
128     }
129 
130     {
131         std::ostringstream oss;
132         int const i = 0;
133         bh::tuple<int const> tuple{i};
134         yap::detail::print_type(oss, tuple);
135         BOOST_CHECK(oss.str() == "int const");
136     }
137 
138     {
139         std::ostringstream oss;
140         int i = 0;
141         bh::tuple<int &> tuple{i};
142         yap::detail::print_type(oss, tuple);
143         BOOST_CHECK(oss.str() == "int &");
144     }
145 
146     {
147         std::ostringstream oss;
148         int const i = 0;
149         bh::tuple<int const &> tuple{i};
150         yap::detail::print_type(oss, tuple);
151         BOOST_CHECK(oss.str() == "int const &");
152     }
153 
154     {
155         user_term<double> unity{1.0};
156         int i_ = 42;
157         user_term<int &&> i{std::move(i_)};
158         user_expr<
159             yap::expr_kind::plus,
160             bh::tuple<user_ref<user_term<double> &>, user_term<int &&>>>
161             expr = unity + std::move(i);
162         user_expr<
163             yap::expr_kind::plus,
164             bh::tuple<
165                 user_ref<user_term<double> &>,
166                 user_expr<
167                     yap::expr_kind::plus,
168                     bh::tuple<
169                         user_ref<user_term<double> &>,
170                         user_term<int &&>>>>>
171             unevaluated_expr = unity + std::move(expr);
172 
173         {
174             std::ostringstream oss;
175             yap::print(oss, unity);
176             BOOST_CHECK(oss.str() == R"(term<double>[=1]
177 )");
178         }
179 
180         {
181             std::ostringstream oss;
182             yap::print(oss, expr);
183             BOOST_CHECK(oss.str() == R"(expr<+>
184     term<double>[=1] &
185     term<int &&>[=42]
186 )");
187         }
188 
189         {
190             std::ostringstream oss;
191             yap::print(oss, unevaluated_expr);
192             BOOST_CHECK(oss.str() == R"(expr<+>
193     term<double>[=1] &
194     expr<+>
195         term<double>[=1] &
196         term<int &&>[=42]
197 )");
198         }
199 
200         user_term<thing> a_thing{bh::make_tuple(thing{})};
201 
202         {
203             std::ostringstream oss;
204             yap::print(oss, a_thing);
205             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
206 )");
207         }
208 
209         user_term<double> const const_unity{1.0};
210         user_expr<
211             yap::expr_kind::plus,
212             bh::tuple<
213                 user_ref<user_term<double> &>,
214                 user_ref<user_term<double> const &>>>
215             nonconst_plus_const = unity + const_unity;
216 
217         {
218             std::ostringstream oss;
219             yap::print(oss, nonconst_plus_const);
220             BOOST_CHECK(oss.str() == R"(expr<+>
221     term<double>[=1] &
222     term<double>[=1] const &
223 )");
224         }
225 
226         auto nonconst_plus_nonconst_plus_const = unity + nonconst_plus_const;
227 
228         {
229             std::ostringstream oss;
230             yap::print(oss, nonconst_plus_nonconst_plus_const);
231             BOOST_CHECK(oss.str() == R"(expr<+>
232     term<double>[=1] &
233     expr<+> &
234         term<double>[=1] &
235         term<double>[=1] const &
236 )");
237         }
238 
239         auto const const_nonconst_plus_const = nonconst_plus_const;
240         auto nonconst_plus_nonconst_plus_const_2 =
241             unity + const_nonconst_plus_const;
242 
243         {
244             std::ostringstream oss;
245             yap::print(oss, nonconst_plus_nonconst_plus_const_2);
246             BOOST_CHECK(oss.str() == R"(expr<+>
247     term<double>[=1] &
248     expr<+> const &
249         term<double>[=1] &
250         term<double>[=1] const &
251 )");
252         }
253     }
254 
255     {
256         term<double> unity{1.0};
257         int i_ = 42;
258         term<int &&> i{std::move(i_)};
259         yap::expression<
260             yap::expr_kind::plus,
261             bh::tuple<ref<term<double> &>, term<int &&>>>
262             expr = unity + std::move(i);
263         yap::expression<
264             yap::expr_kind::plus,
265             bh::tuple<
266                 ref<term<double> &>,
267                 yap::expression<
268                     yap::expr_kind::plus,
269                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
270             unevaluated_expr = unity + std::move(expr);
271 
272         {
273             std::ostringstream oss;
274             yap::print(oss, unity);
275             BOOST_CHECK(oss.str() == R"(term<double>[=1]
276 )");
277         }
278 
279         {
280             std::ostringstream oss;
281             yap::print(oss, expr);
282             BOOST_CHECK(oss.str() == R"(expr<+>
283     term<double>[=1] &
284     term<int &&>[=42]
285 )");
286         }
287 
288         {
289             std::ostringstream oss;
290             yap::print(oss, unevaluated_expr);
291             BOOST_CHECK(oss.str() == R"(expr<+>
292     term<double>[=1] &
293     expr<+>
294         term<double>[=1] &
295         term<int &&>[=42]
296 )");
297         }
298 
299         term<thing> a_thing(thing{});
300 
301         {
302             std::ostringstream oss;
303             yap::print(oss, a_thing);
304             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
305 )");
306         }
307 
308         term<double> const const_unity{1.0};
309         yap::expression<
310             yap::expr_kind::plus,
311             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
312             nonconst_plus_const = unity + const_unity;
313 
314         {
315             std::ostringstream oss;
316             yap::print(oss, nonconst_plus_const);
317             BOOST_CHECK(oss.str() == R"(expr<+>
318     term<double>[=1] &
319     term<double>[=1] const &
320 )");
321         }
322 
323         {
324             using namespace yap::literals;
325             std::ostringstream oss;
326             yap::print(oss, 1_p);
327             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
328 )");
329         }
330     }
331 
332     {
333         term<double> unity{1.0};
334         int i_ = 42;
335         term<int &&> i{std::move(i_)};
336         yap::expression<
337             yap::expr_kind::minus,
338             bh::tuple<ref<term<double> &>, term<int &&>>>
339             expr = unity - std::move(i);
340         yap::expression<
341             yap::expr_kind::minus,
342             bh::tuple<
343                 ref<term<double> &>,
344                 yap::expression<
345                     yap::expr_kind::minus,
346                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
347             unevaluated_expr = unity - std::move(expr);
348 
349         {
350             std::ostringstream oss;
351             yap::print(oss, unity);
352             BOOST_CHECK(oss.str() == R"(term<double>[=1]
353 )");
354         }
355 
356         {
357             std::ostringstream oss;
358             yap::print(oss, expr);
359             BOOST_CHECK(oss.str() == R"(expr<->
360     term<double>[=1] &
361     term<int &&>[=42]
362 )");
363         }
364 
365         {
366             std::ostringstream oss;
367             yap::print(oss, unevaluated_expr);
368             BOOST_CHECK(oss.str() == R"(expr<->
369     term<double>[=1] &
370     expr<->
371         term<double>[=1] &
372         term<int &&>[=42]
373 )");
374         }
375 
376         term<thing> a_thing(thing{});
377 
378         {
379             std::ostringstream oss;
380             yap::print(oss, a_thing);
381             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
382 )");
383         }
384 
385         term<double> const const_unity{1.0};
386         yap::expression<
387             yap::expr_kind::minus,
388             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
389             nonconst_minus_const = unity - const_unity;
390 
391         {
392             std::ostringstream oss;
393             yap::print(oss, nonconst_minus_const);
394             BOOST_CHECK(oss.str() == R"(expr<->
395     term<double>[=1] &
396     term<double>[=1] const &
397 )");
398         }
399 
400         {
401             using namespace yap::literals;
402             std::ostringstream oss;
403             yap::print(oss, 1_p);
404             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
405 )");
406         }
407     }
408 
409     {
410         term<double> unity{1.0};
411         int i_ = 42;
412         term<int &&> i{std::move(i_)};
413         yap::expression<
414             yap::expr_kind::less,
415             bh::tuple<ref<term<double> &>, term<int &&>>>
416             expr = unity < std::move(i);
417         yap::expression<
418             yap::expr_kind::less,
419             bh::tuple<
420                 ref<term<double> &>,
421                 yap::expression<
422                     yap::expr_kind::less,
423                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
424             unevaluated_expr = unity < std::move(expr);
425 
426         {
427             std::ostringstream oss;
428             yap::print(oss, unity);
429             BOOST_CHECK(oss.str() == R"(term<double>[=1]
430 )");
431         }
432 
433         {
434             std::ostringstream oss;
435             yap::print(oss, expr);
436             BOOST_CHECK(oss.str() == R"(expr<<>
437     term<double>[=1] &
438     term<int &&>[=42]
439 )");
440         }
441 
442         {
443             std::ostringstream oss;
444             yap::print(oss, unevaluated_expr);
445             BOOST_CHECK(oss.str() == R"(expr<<>
446     term<double>[=1] &
447     expr<<>
448         term<double>[=1] &
449         term<int &&>[=42]
450 )");
451         }
452 
453         term<thing> a_thing(thing{});
454 
455         {
456             std::ostringstream oss;
457             yap::print(oss, a_thing);
458             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
459 )");
460         }
461 
462         term<double> const const_unity{1.0};
463         yap::expression<
464             yap::expr_kind::less,
465             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
466             nonconst_less_const = unity < const_unity;
467 
468         {
469             std::ostringstream oss;
470             yap::print(oss, nonconst_less_const);
471             BOOST_CHECK(oss.str() == R"(expr<<>
472     term<double>[=1] &
473     term<double>[=1] const &
474 )");
475         }
476 
477         {
478             using namespace yap::literals;
479             std::ostringstream oss;
480             yap::print(oss, 1_p);
481             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
482 )");
483         }
484     }
485 
486     {
487         term<double> unity{1.0};
488         int i_ = 42;
489         term<int &&> i{std::move(i_)};
490         yap::expression<
491             yap::expr_kind::greater,
492             bh::tuple<ref<term<double> &>, term<int &&>>>
493             expr = unity > std::move(i);
494         yap::expression<
495             yap::expr_kind::greater,
496             bh::tuple<
497                 ref<term<double> &>,
498                 yap::expression<
499                     yap::expr_kind::greater,
500                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
501             unevaluated_expr = unity > std::move(expr);
502 
503         {
504             std::ostringstream oss;
505             yap::print(oss, unity);
506             BOOST_CHECK(oss.str() == R"(term<double>[=1]
507 )");
508         }
509 
510         {
511             std::ostringstream oss;
512             yap::print(oss, expr);
513             BOOST_CHECK(oss.str() == R"(expr<>>
514     term<double>[=1] &
515     term<int &&>[=42]
516 )");
517         }
518 
519         {
520             std::ostringstream oss;
521             yap::print(oss, unevaluated_expr);
522             BOOST_CHECK(oss.str() == R"(expr<>>
523     term<double>[=1] &
524     expr<>>
525         term<double>[=1] &
526         term<int &&>[=42]
527 )");
528         }
529 
530         term<thing> a_thing(thing{});
531 
532         {
533             std::ostringstream oss;
534             yap::print(oss, a_thing);
535             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
536 )");
537         }
538 
539         term<double> const const_unity{1.0};
540         yap::expression<
541             yap::expr_kind::greater,
542             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
543             nonconst_greater_const = unity > const_unity;
544 
545         {
546             std::ostringstream oss;
547             yap::print(oss, nonconst_greater_const);
548             BOOST_CHECK(oss.str() == R"(expr<>>
549     term<double>[=1] &
550     term<double>[=1] const &
551 )");
552         }
553 
554         {
555             using namespace yap::literals;
556             std::ostringstream oss;
557             yap::print(oss, 1_p);
558             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
559 )");
560         }
561     }
562 
563     {
564         term<double> unity{1.0};
565         int i_ = 42;
566         term<int &&> i{std::move(i_)};
567         yap::expression<
568             yap::expr_kind::less_equal,
569             bh::tuple<ref<term<double> &>, term<int &&>>>
570             expr = unity <= std::move(i);
571         yap::expression<
572             yap::expr_kind::less_equal,
573             bh::tuple<
574                 ref<term<double> &>,
575                 yap::expression<
576                     yap::expr_kind::less_equal,
577                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
578             unevaluated_expr = unity <= std::move(expr);
579 
580         {
581             std::ostringstream oss;
582             yap::print(oss, unity);
583             BOOST_CHECK(oss.str() == R"(term<double>[=1]
584 )");
585         }
586 
587         {
588             std::ostringstream oss;
589             yap::print(oss, expr);
590             BOOST_CHECK(oss.str() == R"(expr<<=>
591     term<double>[=1] &
592     term<int &&>[=42]
593 )");
594         }
595 
596         {
597             std::ostringstream oss;
598             yap::print(oss, unevaluated_expr);
599             BOOST_CHECK(oss.str() == R"(expr<<=>
600     term<double>[=1] &
601     expr<<=>
602         term<double>[=1] &
603         term<int &&>[=42]
604 )");
605         }
606 
607         term<thing> a_thing(thing{});
608 
609         {
610             std::ostringstream oss;
611             yap::print(oss, a_thing);
612             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
613 )");
614         }
615 
616         term<double> const const_unity{1.0};
617         yap::expression<
618             yap::expr_kind::less_equal,
619             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
620             nonconst_less_equal_const = unity <= const_unity;
621 
622         {
623             std::ostringstream oss;
624             yap::print(oss, nonconst_less_equal_const);
625             BOOST_CHECK(oss.str() == R"(expr<<=>
626     term<double>[=1] &
627     term<double>[=1] const &
628 )");
629         }
630 
631         {
632             using namespace yap::literals;
633             std::ostringstream oss;
634             yap::print(oss, 1_p);
635             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
636 )");
637         }
638     }
639 
640     {
641         term<double> unity{1.0};
642         int i_ = 42;
643         term<int &&> i{std::move(i_)};
644         yap::expression<
645             yap::expr_kind::greater_equal,
646             bh::tuple<ref<term<double> &>, term<int &&>>>
647             expr = unity >= std::move(i);
648         yap::expression<
649             yap::expr_kind::greater_equal,
650             bh::tuple<
651                 ref<term<double> &>,
652                 yap::expression<
653                     yap::expr_kind::greater_equal,
654                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
655             unevaluated_expr = unity >= std::move(expr);
656 
657         {
658             std::ostringstream oss;
659             yap::print(oss, unity);
660             BOOST_CHECK(oss.str() == R"(term<double>[=1]
661 )");
662         }
663 
664         {
665             std::ostringstream oss;
666             yap::print(oss, expr);
667             BOOST_CHECK(oss.str() == R"(expr<>=>
668     term<double>[=1] &
669     term<int &&>[=42]
670 )");
671         }
672 
673         {
674             std::ostringstream oss;
675             yap::print(oss, unevaluated_expr);
676             BOOST_CHECK(oss.str() == R"(expr<>=>
677     term<double>[=1] &
678     expr<>=>
679         term<double>[=1] &
680         term<int &&>[=42]
681 )");
682         }
683 
684         term<thing> a_thing(thing{});
685 
686         {
687             std::ostringstream oss;
688             yap::print(oss, a_thing);
689             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
690 )");
691         }
692 
693         term<double> const const_unity{1.0};
694         yap::expression<
695             yap::expr_kind::greater_equal,
696             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
697             nonconst_greater_equal_const = unity >= const_unity;
698 
699         {
700             std::ostringstream oss;
701             yap::print(oss, nonconst_greater_equal_const);
702             BOOST_CHECK(oss.str() == R"(expr<>=>
703     term<double>[=1] &
704     term<double>[=1] const &
705 )");
706         }
707 
708         {
709             using namespace yap::literals;
710             std::ostringstream oss;
711             yap::print(oss, 1_p);
712             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
713 )");
714         }
715     }
716 
717     {
718         term<double> unity{1.0};
719         int i_ = 42;
720         term<int &&> i{std::move(i_)};
721         yap::expression<
722             yap::expr_kind::equal_to,
723             bh::tuple<ref<term<double> &>, term<int &&>>>
724             expr = unity == std::move(i);
725         yap::expression<
726             yap::expr_kind::equal_to,
727             bh::tuple<
728                 ref<term<double> &>,
729                 yap::expression<
730                     yap::expr_kind::equal_to,
731                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
732             unevaluated_expr = unity == std::move(expr);
733 
734         {
735             std::ostringstream oss;
736             yap::print(oss, unity);
737             BOOST_CHECK(oss.str() == R"(term<double>[=1]
738 )");
739         }
740 
741         {
742             std::ostringstream oss;
743             yap::print(oss, expr);
744             BOOST_CHECK(oss.str() == R"(expr<==>
745     term<double>[=1] &
746     term<int &&>[=42]
747 )");
748         }
749 
750         {
751             std::ostringstream oss;
752             yap::print(oss, unevaluated_expr);
753             BOOST_CHECK(oss.str() == R"(expr<==>
754     term<double>[=1] &
755     expr<==>
756         term<double>[=1] &
757         term<int &&>[=42]
758 )");
759         }
760 
761         term<thing> a_thing(thing{});
762 
763         {
764             std::ostringstream oss;
765             yap::print(oss, a_thing);
766             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
767 )");
768         }
769 
770         term<double> const const_unity{1.0};
771         yap::expression<
772             yap::expr_kind::equal_to,
773             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
774             nonconst_equal_to_const = unity == const_unity;
775 
776         {
777             std::ostringstream oss;
778             yap::print(oss, nonconst_equal_to_const);
779             BOOST_CHECK(oss.str() == R"(expr<==>
780     term<double>[=1] &
781     term<double>[=1] const &
782 )");
783         }
784 
785         {
786             using namespace yap::literals;
787             std::ostringstream oss;
788             yap::print(oss, 1_p);
789             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
790 )");
791         }
792     }
793 
794     {
795         term<double> unity{1.0};
796         int i_ = 42;
797         term<int &&> i{std::move(i_)};
798         yap::expression<
799             yap::expr_kind::not_equal_to,
800             bh::tuple<ref<term<double> &>, term<int &&>>>
801             expr = unity != std::move(i);
802         yap::expression<
803             yap::expr_kind::not_equal_to,
804             bh::tuple<
805                 ref<term<double> &>,
806                 yap::expression<
807                     yap::expr_kind::not_equal_to,
808                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
809             unevaluated_expr = unity != std::move(expr);
810 
811         {
812             std::ostringstream oss;
813             yap::print(oss, unity);
814             BOOST_CHECK(oss.str() == R"(term<double>[=1]
815 )");
816         }
817 
818         {
819             std::ostringstream oss;
820             yap::print(oss, expr);
821             BOOST_CHECK(oss.str() == R"(expr<!=>
822     term<double>[=1] &
823     term<int &&>[=42]
824 )");
825         }
826 
827         {
828             std::ostringstream oss;
829             yap::print(oss, unevaluated_expr);
830             BOOST_CHECK(oss.str() == R"(expr<!=>
831     term<double>[=1] &
832     expr<!=>
833         term<double>[=1] &
834         term<int &&>[=42]
835 )");
836         }
837 
838         term<thing> a_thing(thing{});
839 
840         {
841             std::ostringstream oss;
842             yap::print(oss, a_thing);
843             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
844 )");
845         }
846 
847         term<double> const const_unity{1.0};
848         yap::expression<
849             yap::expr_kind::not_equal_to,
850             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
851             nonconst_not_equal_to_const = unity != const_unity;
852 
853         {
854             std::ostringstream oss;
855             yap::print(oss, nonconst_not_equal_to_const);
856             BOOST_CHECK(oss.str() == R"(expr<!=>
857     term<double>[=1] &
858     term<double>[=1] const &
859 )");
860         }
861 
862         {
863             using namespace yap::literals;
864             std::ostringstream oss;
865             yap::print(oss, 1_p);
866             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
867 )");
868         }
869     }
870 
871     {
872         term<double> unity{1.0};
873         int i_ = 42;
874         term<int &&> i{std::move(i_)};
875         yap::expression<
876             yap::expr_kind::logical_or,
877             bh::tuple<ref<term<double> &>, term<int &&>>>
878             expr = unity || std::move(i);
879         yap::expression<
880             yap::expr_kind::logical_or,
881             bh::tuple<
882                 ref<term<double> &>,
883                 yap::expression<
884                     yap::expr_kind::logical_or,
885                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
886             unevaluated_expr = unity || std::move(expr);
887 
888         {
889             std::ostringstream oss;
890             yap::print(oss, unity);
891             BOOST_CHECK(oss.str() == R"(term<double>[=1]
892 )");
893         }
894 
895         {
896             std::ostringstream oss;
897             yap::print(oss, expr);
898             BOOST_CHECK(oss.str() == R"(expr<||>
899     term<double>[=1] &
900     term<int &&>[=42]
901 )");
902         }
903 
904         {
905             std::ostringstream oss;
906             yap::print(oss, unevaluated_expr);
907             BOOST_CHECK(oss.str() == R"(expr<||>
908     term<double>[=1] &
909     expr<||>
910         term<double>[=1] &
911         term<int &&>[=42]
912 )");
913         }
914 
915         term<thing> a_thing(thing{});
916 
917         {
918             std::ostringstream oss;
919             yap::print(oss, a_thing);
920             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
921 )");
922         }
923 
924         term<double> const const_unity{1.0};
925         yap::expression<
926             yap::expr_kind::logical_or,
927             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
928             nonconst_logical_or_const = unity || const_unity;
929 
930         {
931             std::ostringstream oss;
932             yap::print(oss, nonconst_logical_or_const);
933             BOOST_CHECK(oss.str() == R"(expr<||>
934     term<double>[=1] &
935     term<double>[=1] const &
936 )");
937         }
938 
939         {
940             using namespace yap::literals;
941             std::ostringstream oss;
942             yap::print(oss, 1_p);
943             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
944 )");
945         }
946     }
947 
948     {
949         term<double> unity{1.0};
950         int i_ = 42;
951         term<int &&> i{std::move(i_)};
952         yap::expression<
953             yap::expr_kind::logical_and,
954             bh::tuple<ref<term<double> &>, term<int &&>>>
955             expr = unity && std::move(i);
956         yap::expression<
957             yap::expr_kind::logical_and,
958             bh::tuple<
959                 ref<term<double> &>,
960                 yap::expression<
961                     yap::expr_kind::logical_and,
962                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
963             unevaluated_expr = unity && std::move(expr);
964 
965         {
966             std::ostringstream oss;
967             yap::print(oss, unity);
968             BOOST_CHECK(oss.str() == R"(term<double>[=1]
969 )");
970         }
971 
972         {
973             std::ostringstream oss;
974             yap::print(oss, expr);
975             BOOST_CHECK(oss.str() == R"(expr<&&>
976     term<double>[=1] &
977     term<int &&>[=42]
978 )");
979         }
980 
981         {
982             std::ostringstream oss;
983             yap::print(oss, unevaluated_expr);
984             BOOST_CHECK(oss.str() == R"(expr<&&>
985     term<double>[=1] &
986     expr<&&>
987         term<double>[=1] &
988         term<int &&>[=42]
989 )");
990         }
991 
992         term<thing> a_thing(thing{});
993 
994         {
995             std::ostringstream oss;
996             yap::print(oss, a_thing);
997             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
998 )");
999         }
1000 
1001         term<double> const const_unity{1.0};
1002         yap::expression<
1003             yap::expr_kind::logical_and,
1004             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1005             nonconst_logical_and_const = unity && const_unity;
1006 
1007         {
1008             std::ostringstream oss;
1009             yap::print(oss, nonconst_logical_and_const);
1010             BOOST_CHECK(oss.str() == R"(expr<&&>
1011     term<double>[=1] &
1012     term<double>[=1] const &
1013 )");
1014         }
1015 
1016         {
1017             using namespace yap::literals;
1018             std::ostringstream oss;
1019             yap::print(oss, 1_p);
1020             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1021 )");
1022         }
1023     }
1024 
1025     {
1026         term<double> unity{1.0};
1027         int i_ = 42;
1028         term<int &&> i{std::move(i_)};
1029         yap::expression<
1030             yap::expr_kind::bitwise_and,
1031             bh::tuple<ref<term<double> &>, term<int &&>>>
1032             expr = unity & std::move(i);
1033         yap::expression<
1034             yap::expr_kind::bitwise_and,
1035             bh::tuple<
1036                 ref<term<double> &>,
1037                 yap::expression<
1038                     yap::expr_kind::bitwise_and,
1039                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1040             unevaluated_expr = unity & std::move(expr);
1041 
1042         {
1043             std::ostringstream oss;
1044             yap::print(oss, unity);
1045             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1046 )");
1047         }
1048 
1049         {
1050             std::ostringstream oss;
1051             yap::print(oss, expr);
1052             BOOST_CHECK(oss.str() == R"(expr<&>
1053     term<double>[=1] &
1054     term<int &&>[=42]
1055 )");
1056         }
1057 
1058         {
1059             std::ostringstream oss;
1060             yap::print(oss, unevaluated_expr);
1061             BOOST_CHECK(oss.str() == R"(expr<&>
1062     term<double>[=1] &
1063     expr<&>
1064         term<double>[=1] &
1065         term<int &&>[=42]
1066 )");
1067         }
1068 
1069         term<thing> a_thing(thing{});
1070 
1071         {
1072             std::ostringstream oss;
1073             yap::print(oss, a_thing);
1074             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1075 )");
1076         }
1077 
1078         term<double> const const_unity{1.0};
1079         yap::expression<
1080             yap::expr_kind::bitwise_and,
1081             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1082             nonconst_bitwise_and_const = unity & const_unity;
1083 
1084         {
1085             std::ostringstream oss;
1086             yap::print(oss, nonconst_bitwise_and_const);
1087             BOOST_CHECK(oss.str() == R"(expr<&>
1088     term<double>[=1] &
1089     term<double>[=1] const &
1090 )");
1091         }
1092 
1093         {
1094             using namespace yap::literals;
1095             std::ostringstream oss;
1096             yap::print(oss, 1_p);
1097             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1098 )");
1099         }
1100     }
1101 
1102     {
1103         term<double> unity{1.0};
1104         int i_ = 42;
1105         term<int &&> i{std::move(i_)};
1106         yap::expression<
1107             yap::expr_kind::bitwise_or,
1108             bh::tuple<ref<term<double> &>, term<int &&>>>
1109             expr = unity | std::move(i);
1110         yap::expression<
1111             yap::expr_kind::bitwise_or,
1112             bh::tuple<
1113                 ref<term<double> &>,
1114                 yap::expression<
1115                     yap::expr_kind::bitwise_or,
1116                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1117             unevaluated_expr = unity | std::move(expr);
1118 
1119         {
1120             std::ostringstream oss;
1121             yap::print(oss, unity);
1122             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1123 )");
1124         }
1125 
1126         {
1127             std::ostringstream oss;
1128             yap::print(oss, expr);
1129             BOOST_CHECK(oss.str() == R"(expr<|>
1130     term<double>[=1] &
1131     term<int &&>[=42]
1132 )");
1133         }
1134 
1135         {
1136             std::ostringstream oss;
1137             yap::print(oss, unevaluated_expr);
1138             BOOST_CHECK(oss.str() == R"(expr<|>
1139     term<double>[=1] &
1140     expr<|>
1141         term<double>[=1] &
1142         term<int &&>[=42]
1143 )");
1144         }
1145 
1146         term<thing> a_thing(thing{});
1147 
1148         {
1149             std::ostringstream oss;
1150             yap::print(oss, a_thing);
1151             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1152 )");
1153         }
1154 
1155         term<double> const const_unity{1.0};
1156         yap::expression<
1157             yap::expr_kind::bitwise_or,
1158             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1159             nonconst_bitwise_or_const = unity | const_unity;
1160 
1161         {
1162             std::ostringstream oss;
1163             yap::print(oss, nonconst_bitwise_or_const);
1164             BOOST_CHECK(oss.str() == R"(expr<|>
1165     term<double>[=1] &
1166     term<double>[=1] const &
1167 )");
1168         }
1169 
1170         {
1171             using namespace yap::literals;
1172             std::ostringstream oss;
1173             yap::print(oss, 1_p);
1174             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1175 )");
1176         }
1177     }
1178 
1179     {
1180         term<double> unity{1.0};
1181         int i_ = 42;
1182         term<int &&> i{std::move(i_)};
1183         yap::expression<
1184             yap::expr_kind::bitwise_xor,
1185             bh::tuple<ref<term<double> &>, term<int &&>>>
1186             expr = unity ^ std::move(i);
1187         yap::expression<
1188             yap::expr_kind::bitwise_xor,
1189             bh::tuple<
1190                 ref<term<double> &>,
1191                 yap::expression<
1192                     yap::expr_kind::bitwise_xor,
1193                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1194             unevaluated_expr = unity ^ std::move(expr);
1195 
1196         {
1197             std::ostringstream oss;
1198             yap::print(oss, unity);
1199             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1200 )");
1201         }
1202 
1203         {
1204             std::ostringstream oss;
1205             yap::print(oss, expr);
1206             BOOST_CHECK(oss.str() == R"(expr<^>
1207     term<double>[=1] &
1208     term<int &&>[=42]
1209 )");
1210         }
1211 
1212         {
1213             std::ostringstream oss;
1214             yap::print(oss, unevaluated_expr);
1215             BOOST_CHECK(oss.str() == R"(expr<^>
1216     term<double>[=1] &
1217     expr<^>
1218         term<double>[=1] &
1219         term<int &&>[=42]
1220 )");
1221         }
1222 
1223         term<thing> a_thing(thing{});
1224 
1225         {
1226             std::ostringstream oss;
1227             yap::print(oss, a_thing);
1228             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1229 )");
1230         }
1231 
1232         term<double> const const_unity{1.0};
1233         yap::expression<
1234             yap::expr_kind::bitwise_xor,
1235             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1236             nonconst_bitwise_xor_const = unity ^ const_unity;
1237 
1238         {
1239             std::ostringstream oss;
1240             yap::print(oss, nonconst_bitwise_xor_const);
1241             BOOST_CHECK(oss.str() == R"(expr<^>
1242     term<double>[=1] &
1243     term<double>[=1] const &
1244 )");
1245         }
1246 
1247         {
1248             using namespace yap::literals;
1249             std::ostringstream oss;
1250             yap::print(oss, 1_p);
1251             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1252 )");
1253         }
1254     }
1255 
1256     {
1257         term<double> unity{1.0};
1258         int i_ = 42;
1259         term<int &&> i{std::move(i_)};
1260         yap::expression<
1261             yap::expr_kind::comma,
1262             bh::tuple<ref<term<double> &>, term<int &&>>>
1263             expr = (unity, std::move(i));
1264         yap::expression<
1265             yap::expr_kind::comma,
1266             bh::tuple<
1267                 ref<term<double> &>,
1268                 yap::expression<
1269                     yap::expr_kind::comma,
1270                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1271             unevaluated_expr = (unity, std::move(expr));
1272 
1273         {
1274             std::ostringstream oss;
1275             yap::print(oss, unity);
1276             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1277 )");
1278         }
1279 
1280         {
1281             std::ostringstream oss;
1282             yap::print(oss, expr);
1283             BOOST_CHECK(oss.str() == R"(expr<,>
1284     term<double>[=1] &
1285     term<int &&>[=42]
1286 )");
1287         }
1288 
1289         {
1290             std::ostringstream oss;
1291             yap::print(oss, unevaluated_expr);
1292             BOOST_CHECK(oss.str() == R"(expr<,>
1293     term<double>[=1] &
1294     expr<,>
1295         term<double>[=1] &
1296         term<int &&>[=42]
1297 )");
1298         }
1299 
1300         term<thing> a_thing(thing{});
1301 
1302         {
1303             std::ostringstream oss;
1304             yap::print(oss, a_thing);
1305             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1306 )");
1307         }
1308 
1309         term<double> const const_unity{1.0};
1310         yap::expression<
1311             yap::expr_kind::comma,
1312             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1313             nonconst_comma_const = (unity, const_unity);
1314 
1315         {
1316             std::ostringstream oss;
1317             yap::print(oss, nonconst_comma_const);
1318             BOOST_CHECK(oss.str() == R"(expr<,>
1319     term<double>[=1] &
1320     term<double>[=1] const &
1321 )");
1322         }
1323 
1324         {
1325             using namespace yap::literals;
1326             std::ostringstream oss;
1327             yap::print(oss, 1_p);
1328             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1329 )");
1330         }
1331     }
1332 
1333     {
1334         term<double> unity{1.0};
1335         int i_ = 42;
1336         term<int &&> i{std::move(i_)};
1337         yap::expression<
1338             yap::expr_kind::mem_ptr,
1339             bh::tuple<ref<term<double> &>, term<int &&>>>
1340             expr = unity->*std::move(i);
1341         yap::expression<
1342             yap::expr_kind::mem_ptr,
1343             bh::tuple<
1344                 ref<term<double> &>,
1345                 yap::expression<
1346                     yap::expr_kind::mem_ptr,
1347                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1348             unevaluated_expr = unity->*std::move(expr);
1349 
1350         {
1351             std::ostringstream oss;
1352             yap::print(oss, unity);
1353             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1354 )");
1355         }
1356 
1357         {
1358             std::ostringstream oss;
1359             yap::print(oss, expr);
1360             BOOST_CHECK(oss.str() == R"(expr<->*>
1361     term<double>[=1] &
1362     term<int &&>[=42]
1363 )");
1364         }
1365 
1366         {
1367             std::ostringstream oss;
1368             yap::print(oss, unevaluated_expr);
1369             BOOST_CHECK(oss.str() == R"(expr<->*>
1370     term<double>[=1] &
1371     expr<->*>
1372         term<double>[=1] &
1373         term<int &&>[=42]
1374 )");
1375         }
1376 
1377         term<thing> a_thing(thing{});
1378 
1379         {
1380             std::ostringstream oss;
1381             yap::print(oss, a_thing);
1382             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1383 )");
1384         }
1385 
1386         term<double> const const_unity{1.0};
1387         yap::expression<
1388             yap::expr_kind::mem_ptr,
1389             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1390             nonconst_mem_ptr_const = unity->*const_unity;
1391 
1392         {
1393             std::ostringstream oss;
1394             yap::print(oss, nonconst_mem_ptr_const);
1395             BOOST_CHECK(oss.str() == R"(expr<->*>
1396     term<double>[=1] &
1397     term<double>[=1] const &
1398 )");
1399         }
1400 
1401         {
1402             using namespace yap::literals;
1403             std::ostringstream oss;
1404             yap::print(oss, 1_p);
1405             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1406 )");
1407         }
1408     }
1409 
1410     {
1411         term<double> unity{1.0};
1412         int i_ = 42;
1413         term<int &&> i{std::move(i_)};
1414         yap::expression<
1415             yap::expr_kind::assign,
1416             bh::tuple<ref<term<double> &>, term<int &&>>>
1417             expr = unity = std::move(i);
1418         yap::expression<
1419             yap::expr_kind::assign,
1420             bh::tuple<
1421                 ref<term<double> &>,
1422                 yap::expression<
1423                     yap::expr_kind::assign,
1424                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1425             unevaluated_expr = unity = std::move(expr);
1426 
1427         {
1428             std::ostringstream oss;
1429             yap::print(oss, unity);
1430             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1431 )");
1432         }
1433 
1434         {
1435             std::ostringstream oss;
1436             yap::print(oss, expr);
1437             BOOST_CHECK(oss.str() == R"(expr<=>
1438     term<double>[=1] &
1439     term<int &&>[=42]
1440 )");
1441         }
1442 
1443         {
1444             std::ostringstream oss;
1445             yap::print(oss, unevaluated_expr);
1446             BOOST_CHECK(oss.str() == R"(expr<=>
1447     term<double>[=1] &
1448     expr<=>
1449         term<double>[=1] &
1450         term<int &&>[=42]
1451 )");
1452         }
1453 
1454         term<thing> a_thing(thing{});
1455 
1456         {
1457             std::ostringstream oss;
1458             yap::print(oss, a_thing);
1459             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1460 )");
1461         }
1462 
1463         {
1464             using namespace yap::literals;
1465             std::ostringstream oss;
1466             yap::print(oss, 1_p);
1467             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1468 )");
1469         }
1470     }
1471 
1472     {
1473         term<double> unity{1.0};
1474         int i_ = 42;
1475         term<int &&> i{std::move(i_)};
1476         yap::expression<
1477             yap::expr_kind::shift_left_assign,
1478             bh::tuple<ref<term<double> &>, term<int &&>>>
1479             expr = unity <<= std::move(i);
1480         yap::expression<
1481             yap::expr_kind::shift_left_assign,
1482             bh::tuple<
1483                 ref<term<double> &>,
1484                 yap::expression<
1485                     yap::expr_kind::shift_left_assign,
1486                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1487             unevaluated_expr = unity <<= std::move(expr);
1488 
1489         {
1490             std::ostringstream oss;
1491             yap::print(oss, unity);
1492             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1493 )");
1494         }
1495 
1496         {
1497             std::ostringstream oss;
1498             yap::print(oss, expr);
1499             BOOST_CHECK(oss.str() == R"(expr<<<=>
1500     term<double>[=1] &
1501     term<int &&>[=42]
1502 )");
1503         }
1504 
1505         {
1506             std::ostringstream oss;
1507             yap::print(oss, unevaluated_expr);
1508             BOOST_CHECK(oss.str() == R"(expr<<<=>
1509     term<double>[=1] &
1510     expr<<<=>
1511         term<double>[=1] &
1512         term<int &&>[=42]
1513 )");
1514         }
1515 
1516         term<thing> a_thing(thing{});
1517 
1518         {
1519             std::ostringstream oss;
1520             yap::print(oss, a_thing);
1521             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1522 )");
1523         }
1524 
1525         term<double> const const_unity{1.0};
1526         yap::expression<
1527             yap::expr_kind::shift_left_assign,
1528             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1529             nonconst_shift_left_assign_const = unity <<= const_unity;
1530 
1531         {
1532             std::ostringstream oss;
1533             yap::print(oss, nonconst_shift_left_assign_const);
1534             BOOST_CHECK(oss.str() == R"(expr<<<=>
1535     term<double>[=1] &
1536     term<double>[=1] const &
1537 )");
1538         }
1539 
1540         {
1541             using namespace yap::literals;
1542             std::ostringstream oss;
1543             yap::print(oss, 1_p);
1544             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1545 )");
1546         }
1547     }
1548 
1549     {
1550         term<double> unity{1.0};
1551         int i_ = 42;
1552         term<int &&> i{std::move(i_)};
1553         yap::expression<
1554             yap::expr_kind::shift_right_assign,
1555             bh::tuple<ref<term<double> &>, term<int &&>>>
1556             expr = unity >>= std::move(i);
1557         yap::expression<
1558             yap::expr_kind::shift_right_assign,
1559             bh::tuple<
1560                 ref<term<double> &>,
1561                 yap::expression<
1562                     yap::expr_kind::shift_right_assign,
1563                     bh::tuple<ref<term<double> &>, term<int &&>>>>>
1564             unevaluated_expr = unity >>= std::move(expr);
1565 
1566         {
1567             std::ostringstream oss;
1568             yap::print(oss, unity);
1569             BOOST_CHECK(oss.str() == R"(term<double>[=1]
1570 )");
1571         }
1572 
1573         {
1574             std::ostringstream oss;
1575             yap::print(oss, expr);
1576             BOOST_CHECK(oss.str() == R"(expr<>>=>
1577     term<double>[=1] &
1578     term<int &&>[=42]
1579 )");
1580         }
1581 
1582         {
1583             std::ostringstream oss;
1584             yap::print(oss, unevaluated_expr);
1585             BOOST_CHECK(oss.str() == R"(expr<>>=>
1586     term<double>[=1] &
1587     expr<>>=>
1588         term<double>[=1] &
1589         term<int &&>[=42]
1590 )");
1591         }
1592 
1593         term<thing> a_thing(thing{});
1594 
1595         {
1596             std::ostringstream oss;
1597             yap::print(oss, a_thing);
1598             BOOST_CHECK(fix_tti(oss.str()) == R"(term<thing>[=<<unprintable-value>>]
1599 )");
1600         }
1601 
1602         term<double> const const_unity{1.0};
1603         yap::expression<
1604             yap::expr_kind::shift_right_assign,
1605             bh::tuple<ref<term<double> &>, ref<term<double> const &>>>
1606             nonconst_shift_right_assign_const = unity >>= const_unity;
1607 
1608         {
1609             std::ostringstream oss;
1610             yap::print(oss, nonconst_shift_right_assign_const);
1611             BOOST_CHECK(oss.str() == R"(expr<>>=>
1612     term<double>[=1] &
1613     term<double>[=1] const &
1614 )");
1615         }
1616 
1617         {
1618             using namespace yap::literals;
1619             std::ostringstream oss;
1620             yap::print(oss, 1_p);
1621             BOOST_CHECK(fix_tti(oss.str()) == R"(term<boost::yap::placeholder<1>>[=1]
1622 )");
1623         }
1624     }
1625 
1626     {
1627         using namespace yap::literals;
1628         std::ostringstream oss;
1629         yap::print(oss, replace_placeholders(1_p + 2_p,7,8));
1630         BOOST_CHECK(fix_tti(oss.str()) == R"(expr<+>
1631     term<int>[=7]
1632     term<int>[=8]
1633 )");
1634     }
1635 
1636     return 0;
1637 }
1638