C++ Library Extensions 2022.12.09
To help learn modern C++ programming
33-variant_tuple_output.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <type_traits>
3#include <tuple>
4#include <variant>
5
6/*
7 When you overload operators for C++ class,
8 you should be EXTREMELY CAREFUL for recursive function call.
9 Most of the time, it is valid operation. But in some rare cases,
10 it can cause trouble to your application development.
11
12 Operator overloading at global scope is VERY DANGEROUS PRACTICE.
13 You should almost always prevent operator overloading at global scope.
14*/
15namespace tutorial
16{
17 // remove reference and const volatile from type Type
18 template<typename Type>
19 using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<Type>>;
20
21 template<typename Type>
23 {
24 static constexpr bool value = false;
25 };
26
27 template<typename... Types>
28 struct is_variant_st<std::variant<Types...>>
29 {
30 static constexpr bool value = true;
31 };
32
33 template<typename Type>
35
36 template<typename Type>
38 {
39 static constexpr bool value = false;
40 };
41
42 template<typename... Types>
43 struct is_tuple_st<std::tuple<Types...>>
44 {
45 static constexpr bool value = true;
46 };
47
48 template<typename Type>
50
51 template<typename... Types>
52 void print_tuple(std::ostream& os, const std::tuple<Types...>& tpl);
53
54 template<typename Type, typename... Types>
55 void print_variant(std::ostream& os, const std::variant<Type, Types...>& vrt);
56
57 template<size_t StartIndex, size_t EndIndex>
59 {
60 template<typename TupleType>
61 static void print_tuple(std::ostream& os, const TupleType& tpl)
62 {
63 if constexpr( StartIndex != EndIndex )
64 {
65 auto& e = std::get<StartIndex>(tpl);
66 // When you use operator overloading, you have to be extremely careful
67 // of recurive function-call
68 // os << e; <-- is recursive function-call
69 using ele_t = decltype(e);
70
71 if constexpr(is_tuple_v<ele_t>)
72 {
74 }
75 else if constexpr(is_variant_v<ele_t>)
76 {
78 }
79 else
80 {
81 os << e;
82 }
83 }
84
85 if constexpr(StartIndex + 1 < EndIndex)
86 {
87 os << ", ";
88
90 }
91 }
92
93 template<typename VariantType>
94 static void print_variant(std::ostream& os, const VariantType& vrt)
95 {
96 if constexpr(StartIndex != EndIndex)
97 {
98 if(auto ptr = std::get_if<StartIndex>(&vrt))
99 {
100 // os << *ptr; <-- is recursive function-call
101 using ele_t = decltype(*ptr);
102
103 if constexpr(is_variant_v<ele_t>)
104 {
105 tutorial::print_variant(os, *ptr); // recursion
106 }
107 else if constexpr(is_tuple_v<ele_t>)
108 {
109 tutorial::print_tuple(os, *ptr); // recursion
110 }
111 else
112 {
113 os << *ptr; // this is not recursion
114 }
115
116 return;
117 }
118 }
119
120 if constexpr(StartIndex + 1 < EndIndex )
121 {
123 }
124 }
125
126 };
127
128 template<typename... Types>
129 void print_tuple(std::ostream& os, const std::tuple<Types...>& tpl)
130 {
131 if constexpr(sizeof...(Types) == 0)
132 {
133 os << "{ }";
134 }
135 else
136 {
137 os << "{";
138 static_loop<0, sizeof...(Types)>::template print_tuple(os, tpl);
139 os << "}";
140 }
141
142 }
143
144 template<typename Type, typename... Types>
145 void print_variant(std::ostream& os, const std::variant<Type, Types...>& vrt)
146 {
147 // if vrt is not initialized
148 // we cannot access the element
149 if(vrt.index() != std::variant_npos)
150 static_loop<0, sizeof...(Types) + 1>::template print_variant(os, vrt);
151 }
152
153 template<typename... Types>
154 std::ostream& operator<<(std::ostream& os, const std::tuple<Types...>& tpl)
155 {
156 print_tuple(os, tpl);
157 return os;
158 }
159
160 template<typename Type, typename... Types>
161 std::ostream& operator<<(std::ostream& os, const std::variant<Type, Types...>& vrt)
162 {
163 print_variant(os, vrt);
164
165 return os;
166 }
167
168} // end of namespace tutorial
169
171{
172 using name_t = std::string;
173 using age_t = int;
174 using weight_t = double;
175
176 using tuple_t = std::tuple<name_t, age_t, weight_t>;
177 using variant_t = std::variant<name_t, age_t, weight_t>;
178
179 tuple_t t{ "Sophie Turner", 20, 56.5};
180
181 variant_t v { "Thomas Kim"};
182
183 {
184 using namespace tutorial;
185
186 std::cout << "t = " << t << std::endl;
187 std::cout << "v = " << v << std::endl;
188 }
189}
190
192{
193 using name_t = std::string;
194 using age_t = int;
195 using weight_t = double;
196
197 using tpl_t = std::tuple<name_t, age_t, weight_t>;
198 using vrt_t = std::variant<name_t, age_t, weight_t>;
199
200 // tuple_t is a tuple with name_t, another tuple tpl_t, a variant vrt_t as
201 // its element types
202 using tuple_t = std::tuple<name_t, tpl_t, vrt_t>;
203
204 // variant_t is a variant with name_t, a tuple tpl_t, another variant vrt_t
205 // as its element types
206 using variant_t = std::variant<name_t, tpl_t, vrt_t>;
207
208 tuple_t t { "Advanced Tuple", tpl_t{"Sophie Turner", 20, 56.7}, vrt_t{"Steven Lee"} };
209
210 variant_t v { tpl_t{ "Advanced Variant", 1, 22.0 / 7.0} };
211
212 // do not do this
213 // using namespace tutorial;
214
215 {
216 // always confine using declaraction of the namespace
217 using namespace tutorial;
218
219 std::cout << "t = " << t << std::endl;
220 std::cout << "v = " << v << std::endl;
221 }
222}
223
224int main()
225{
226 // test_simple_tuple_variant();
227
229}
230
auto & cout
void test_advanced_tuple_variant()
void test_simple_tuple_variant()
auto & endl
constexpr bool is_tuple_v
constexpr bool is_variant_v
std::remove_cv_t< std::remove_reference_t< Type > > remove_cv_ref_t
void print_tuple(std::ostream &os, const std::tuple< Types... > &tpl)
std::ostream & operator<<(std::ostream &os, const std::tuple< Types... > &tpl)
void print_variant(std::ostream &os, const std::variant< Type, Types... > &vrt)
static constexpr bool value
static void print_variant(std::ostream &os, const VariantType &vrt)
static void print_tuple(std::ostream &os, const TupleType &tpl)