• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Louis Dionne 2013-2017
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
4 
5 #include <boost/hana/assert.hpp>
6 #include <boost/hana/core/tag_of.hpp>
7 #include <boost/hana/integral_constant.hpp>
8 #include <boost/hana/minus.hpp>
9 #include <boost/hana/not_equal.hpp>
10 #include <boost/hana/tuple.hpp>
11 
12 #include <cstddef>
13 #include <iostream>
14 #include <sstream>
15 namespace hana = boost::hana;
16 
17 
18 //! [setup]
19 template <typename Tag>
20 struct print_impl {
21   template <typename X>
applyprint_impl22   static void apply(std::ostream&, X const&) {
23     // possibly some default implementation
24   }
25 };
26 
27 template <typename X>
print(std::ostream & os,X x)28 void print(std::ostream& os, X x) {
29   using Tag = typename hana::tag_of<X>::type;
30   print_impl<Tag>::apply(os, x);
31 }
32 //! [setup]
33 
34 //! [vector]
35 struct vector_tag;
36 
37 struct vector0 {
38   using hana_tag = vector_tag;
39   static constexpr std::size_t size = 0;
40 };
41 
42 template <typename T1>
43 struct vector1 {
44   T1 t1;
45   using hana_tag = vector_tag;
46   static constexpr std::size_t size = 1;
47 
48   template <typename Index>
operator []vector149   auto const& operator[](Index i) const {
50     static_assert(i == 0u, "index out of bounds");
51     return t1;
52   }
53 };
54 
55 template <typename T1, typename T2>
56 struct vector2 {
57   T1 t1; T2 t2;
58   using hana_tag = vector_tag;
59   static constexpr std::size_t size = 2;
60 
61   // Using Hana as a backend to simplify the example.
62   template <typename Index>
operator []vector263   auto const& operator[](Index i) const {
64     return *hana::make_tuple(&t1, &t2)[i];
65   }
66 };
67 
68 // and so on...
69 //! [vector]
70 
71 //! [customize]
72 template <>
73 struct print_impl<vector_tag> {
74   template <typename vectorN>
applyprint_impl75   static void apply(std::ostream& os, vectorN xs) {
76     auto N = hana::size_c<vectorN::size>;
77 
78     os << "[";
79     N.times.with_index([&](auto i) {
80       os << xs[i];
81       if (i != N - hana::size_c<1>) os << ", ";
82     });
83     os << "]";
84   }
85 };
86 //! [customize]
87 
88 #if 0
89 //! [customize-when]
90 template <typename Tag>
91 struct print_impl<Tag, hana::when<Tag represents some kind of sequence>> {
92   template <typename Seq>
93   static void apply(std::ostream& os, Seq xs) {
94     // Some implementation for any sequence
95   }
96 };
97 //! [customize-when]
98 #endif
99 
main()100 int main() {
101   {
102     std::stringstream ss;
103     vector0 v0;
104     print(ss, v0);
105     BOOST_HANA_RUNTIME_CHECK(ss.str() == "[]");
106   }
107 
108   {
109     std::stringstream ss;
110     vector1<int> v1{1};
111     print(ss, v1);
112     BOOST_HANA_RUNTIME_CHECK(ss.str() == "[1]");
113   }
114 
115   {
116     std::stringstream ss;
117     vector2<int, char> v2{1, 'x'};
118     print(ss, v2);
119     BOOST_HANA_RUNTIME_CHECK(ss.str() == "[1, x]");
120   }
121 }
122 
123 namespace old_way {
124 //! [old_way]
print(std::ostream & os,vector0)125 void print(std::ostream& os, vector0)
126 { os << "[]"; }
127 
128 template <typename T1>
print(std::ostream & os,vector1<T1> v)129 void print(std::ostream& os, vector1<T1> v)
130 { os << "[" << v.t1 << "]"; }
131 
132 template <typename T1, typename T2>
print(std::ostream & os,vector2<T1,T2> v)133 void print(std::ostream& os, vector2<T1, T2> v)
134 { os << "[" << v.t1 << ", " << v.t2 << "]"; }
135 
136 // and so on...
137 //! [old_way]
138 }
139 
140 namespace preconditions {
141 //! [preconditions]
142 template <typename X>
print(std::ostream & os,X x)143 void print(std::ostream& os, X x) {
144   // **** check some precondition ****
145 
146   // The precondition only has to be checked here; implementations
147   // can assume their arguments to always be sane.
148 
149   using Tag = typename hana::tag_of<X>::type;
150   print_impl<Tag>::apply(os, x);
151 }
152 //! [preconditions]
153 }
154 
155 namespace function_objects {
156 //! [function_objects]
157 // Defining a function object is only needed once and implementations do not
158 // have to worry about static initialization and other painful tricks.
159 struct print_t {
160   template <typename X>
operator ()function_objects::print_t161   void operator()(std::ostream& os, X x) const {
162     using Tag = typename hana::tag_of<X>::type;
163     print_impl<Tag>::apply(os, x);
164   }
165 };
166 constexpr print_t print{};
167 //! [function_objects]
168 
169 static_assert(sizeof(print) || true, "remove unused variable print warning");
170 }
171