C++ Library Extensions 2022.12.09
To help learn modern C++ programming
30-visit.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2
5
6namespace tpf::types
7{
8 template<typename Type>
9 struct is_pair_type_st
10 {
11 static constexpr bool value = false;
12 };
13
14 template<typename Type_1, typename Type_2>
15 struct is_pair_type_st<std::pair<Type_1, Type_2>>
16 {
17 static constexpr bool value = true;
18 };
19
20 template<typename Type>
21 constexpr bool is_pair_type_v = is_pair_type_st<remove_cv_ref_t<Type>>::value;
22
23 template<typename Type>
24 struct is_variant_type_st
25 {
26 static constexpr bool value = false;
27 };
28
29 template<typename... Types>
30 struct is_variant_type_st<std::variant<Types...>>
31 {
32 static constexpr bool value = true;
33 };
34
35 template<typename Type>
36 constexpr bool is_variant_type_v = is_variant_type_st<remove_cv_ref_t<Type>>::value;
37
38 template<typename Type, typename ReturnType = void>
39 using enable_if_pair_t = std::enable_if_t<is_pair_type_v<Type>, ReturnType>;
40
41 template<typename Type, typename ReturnType = void>
42 using enable_if_variant_t = std::enable_if_t<is_variant_type_v<Type>, ReturnType>;
43
44 template<size_t StartIndex, size_t EndIndex>
45 struct compile_time_loop
46 {
47 // this function is enabled only when VariantType is std::variant<Types...>
48 template<typename VisitorType, typename VariantType>
49 static enable_if_variant_t<VariantType>
50 visit_variant(VisitorType&& visitor, VariantType&& vt)
51 {
52 if constexpr(StartIndex < EndIndex)
53 {
54 if(auto ptr = std::get_if<StartIndex>(&vt))
55 {
56 // auto& visit = std::get<StartIndex>(visitor.m_visitors); visit(*ptr);
57 std::get<StartIndex>(visitor.m_visitors)(*ptr);
58 return;
59 }
60 }
61
62 if constexpr (StartIndex + 1 < EndIndex)
63 {
65 visit_variant(std::forward<VisitorType>(visitor) , std::forward<VariantType>(vt));
66 }
67 }
68
69 // this function is enabled only when PairType is std::pair<Type_1, Type_2>
70 template<typename VisitorType, typename PairType>
72 visit_variant(VisitorType&& visitor, PairType&& pair)
73 {
74 if constexpr(StartIndex < EndIndex)
75 {
76 auto& [key, vt] = std::forward<PairType>(pair);
77
78 if(auto ptr = std::get_if<StartIndex>(&vt))
79 {
80 // auto& visit = std::get<StartIndex>(visitor.m_visitors); visit(*ptr);
81 std::get<StartIndex>(visitor.m_visitors)(key, *ptr);
82 return;
83 }
84 }
85
86 if constexpr (StartIndex + 1 < EndIndex)
87 {
89 visit_variant(std::forward<VisitorType>(visitor) , std::forward<PairType>(pair));
90 }
91 }
92
93 }; // end of struct compile_time_loop
94
95 // this function is enabled only when VariantType is std::variant<Types...>
96 template<typename VisitorType, typename VariantType>
97 enable_if_variant_t<VariantType>
98 visit(VisitorType&& visitor, VariantType&& vt)
99 {
100 using variant_t = remove_cv_ref_t<VariantType>;
101 // cppreference.com - std::variant_size_v
102 // https://en.cppreference.com/w/cpp/utility/variant/variant_size
103 constexpr size_t VariantSize = std::variant_size_v<variant_t>;
104
105 compile_time_loop<0, VariantSize>:: template
106 visit_variant(std::forward<VisitorType>(visitor), std::forward<VariantType>(vt));
107 }
108
109 // this function is enabled only when PairType is std::pair<Type_1, Type_2>
110 template<typename VisitorType, typename PairType>
111 enable_if_pair_t<PairType>
112 visit(VisitorType&& visitor, PairType&& pair)
113 {
114 using pair_t = remove_cv_ref_t<PairType>;
115 using variant_t = typename pair_t::second_type;
116
117 // cppreference.com - std::variant_size_v
118 // https://en.cppreference.com/w/cpp/utility/variant/variant_size
119 constexpr size_t VariantSize = std::variant_size_v<variant_t>;
120
122 visit_variant(std::forward<VisitorType>(visitor), std::forward<PairType>(pair));
123 }
124
125 template<typename... VisitorTypes>
126 struct overloaded
127 {
128 using vistors_t = std::tuple<VisitorTypes...>;
129
131
132 overloaded(VisitorTypes... visitors):
133 m_visitors{ std::move(visitors)...} { }
134
135 template<typename ContainerType>
136 void for_each(ContainerType&& container)
137 {
138 for(decltype(auto) vt:
139 std::forward<ContainerType>(container))
140 {
141 types::visit(*this, vt);
142 }
143 }
144 };
145
146 // template argument deduction guide
147 // this feature was introduced to C++17 Standards
148 template<typename... VisitorTypes>
149 overloaded(VisitorTypes...) -> overloaded<VisitorTypes...>;
150
151} // end of namespace tpf::types
152
153namespace types = tpf::types;
154
156{
157 using name_t = const char*;
158 using age_t = int;
159 using weight_t = double;
160 using variant_t = std::variant<name_t, age_t, weight_t>;
161
162 using container_t = std::vector<variant_t>;
163
164 container_t info;
165
166 info.emplace_back("Thomas Kim");
167 info.emplace_back(30);
168 info.emplace_back(60.5);
169 info.emplace_back("Sophie Turner");
170 info.emplace_back(20);
171 info.emplace_back(56.7);
172
174 auto endl = tpf::endl;
175
176 // we now have to concern about
177 // the order of the lambda functions
178 types::overloaded handle_info_auto_ref
179 {
180 [&stream, &endl](auto& name)
181 {
182 stream <<"Name is " << name << endl;
183 },
184
185 [&stream, &endl](auto& age)
186 {
187 stream <<"Age is " << age << endl;
188 },
189
190 [&stream, &endl](auto& weight)
191 {
192 stream << "Weight is " << weight << endl;
193 }
194 };
195
196 types::overloaded handle_info_const_auto_ref
197 {
198 [&stream, &endl](const auto& name)
199 {
200 stream <<"Name is " << name << endl;
201 },
202
203 [&stream, &endl](const auto& age)
204 {
205 stream <<"Age is " << age << endl;
206 },
207
208 [&stream, &endl](const auto& weight)
209 {
210 stream << "Weight is " << weight << endl;
211 }
212 };
213
214 for(const auto& vt: info)
215 {
216 types::visit(handle_info_const_auto_ref, vt);
217 }
218
219 stream << endl;
220
221 for(auto& vt: info)
222 {
223 types::visit(handle_info_auto_ref, vt);
224 }
225
226 stream << endl;
227}
228
230{
231 using name_t = const char*;
232 using age_t = int;
233 using weight_t = double;
234 using variant_t = std::variant<name_t, age_t, weight_t>;
235
236 using container_t = std::vector<variant_t>;
237
238 container_t info;
239
240 info.emplace_back("Thomas Kim");
241 info.emplace_back(30);
242 info.emplace_back(60.5);
243 info.emplace_back("Sophie Turner");
244 info.emplace_back(20);
245 info.emplace_back(56.7);
246
248 auto endl = tpf::endl;
249
250 // we now have to concern about
251 // the order of the lambda functions
252 types::overloaded handle_info
253 {
254 [&stream, &endl](auto&& name)
255 {
256 stream <<"Name is " << name << endl;
257 stream <<"Type: " << Tpf_GetTypeCategory(name) << endl;
258 },
259
260 [&stream, &endl](auto&& age)
261 {
262 stream <<"Age is " << age << endl;
263 stream <<"Type: " << Tpf_GetTypeCategory(age) << endl;
264 },
265
266 [&stream, &endl](auto&& weight)
267 {
268 stream << "Weight is " << weight << endl;
269 stream <<"Type: " << Tpf_GetTypeCategory(weight) << endl;
270 }
271 };
272
273
274 handle_info.for_each(info);
275
276 stream << endl;
277}
278
280{
281 using name_t = const char*;
282 using age_t = int;
283 using weight_t = double;
284 using variant_t = std::variant<name_t, age_t, weight_t>;
285
286 using container_t = std::set<variant_t>;
287
288 container_t info;
289
290 info.emplace("Thomas Kim");
291 info.emplace(30);
292 info.emplace(60.5);
293 info.emplace("Sophie Turner");
294 info.emplace(20);
295 info.emplace(56.7);
296
298 auto endl = tpf::endl;
299
300 // we now have to concern about
301 // the order of the lambda functions
302 types::overloaded handle_info
303 {
304 [&stream, &endl](auto&& name)
305 {
306 stream <<"Name is " << name << endl;
307 stream <<"Type: " << Tpf_GetTypeCategory(name) << endl;
308 },
309
310 [&stream, &endl](auto&& age)
311 {
312 stream <<"Age is " << age << endl;
313 stream <<"Type: " << Tpf_GetTypeCategory(age) << endl;
314 },
315
316 [&stream, &endl](auto&& weight)
317 {
318 stream << "Weight is " << weight << endl;
319 stream <<"Type: " << Tpf_GetTypeCategory(weight) << endl;
320 }
321 };
322
323 handle_info.for_each(info);
324
325 stream << endl;
326
327 // C++2a Standard: Fundamentals of C++ Template Metaprogramming 1/N (039)
328 // https://www.youtube.com/watch?v=nJuXE4VEYLI&t=237s
329 handle_info.for_each( types::reverse(info) );
330
331 stream << endl;
332
333}
334
336{
337 using key_t = const char*;
338 using name_t = const char*;
339 using age_t = int;
340 using weight_t = double;
341 using variant_t = std::variant<name_t, age_t, weight_t>;
342
343 using container_t = std::map<key_t, variant_t>;
344
345 container_t info;
346
347 info["Programmer"] = "Thomas Kim";
348 info["Age"] = 30;
349 info["Weight"] = 60.5;
350 info["Actress"] = "Sophie Turner";
351 info["Her age"] = 20;
352 info["Her weight"] = 56.7;
353
355 auto endl = tpf::endl;
356
357 // we now have to concern about
358 // the order of the lambda functions
359 types::overloaded handle_info
360 {
361 [&stream, &endl](auto&& key, auto&& name)
362 {
363 stream << key << " is " << name << endl;
364 },
365
366 [&stream, &endl](auto&& key, auto&& age)
367 {
368 stream << key << " is " << age << endl;
369 },
370
371 [&stream, &endl](auto&& key, auto&& weight)
372 {
373 stream << key << " is " << weight << endl;
374 }
375 };
376
377 handle_info.for_each(info);
378
379 stream << endl;
380}
381
382int main()
383{
384 // stream <<"container vector " << endl;
385 // test_visit_simplified();
386
387 // stream <<"\ncontainer set " << endl;
388 // test_visit_simplified_set();
389
391}
void test_visit_basic()
Definition: 30-visit.cpp:155
void test_visit_simplified_map()
Definition: 30-visit.cpp:335
tpf::sstream stream
Definition: 30-visit.cpp:3
auto endl
Definition: 30-visit.cpp:4
void test_visit_simplified()
Definition: 30-visit.cpp:229
void test_visit_simplified_set()
Definition: 30-visit.cpp:279
int main()
Definition: 30-visit.cpp:382
constexpr auto reverse(sequence< ms... > mm, sequence< rs... >)
Definition: cpg_types.hpp:4248
Type to string name conversions are defined.
Definition: 31-visit.cpp:7
std::enable_if_t< is_variant_type_v< Type >, ReturnType > enable_if_variant_t
Definition: 31-visit.cpp:62
std::enable_if_t< is_pair_type_v< Type >, ReturnType > enable_if_pair_t
Definition: 31-visit.cpp:56
constexpr bool is_variant_type_v
Definition: 31-visit.cpp:53
enable_if_variant_t< VariantType > visit(VisitorType &&visitor, VariantType &&vt)
Definition: 31-visit.cpp:118
overloaded(VisitorTypes...) -> overloaded< VisitorTypes... >
enable_if_pair_t< PairType > visit(VisitorType &&visitor, PairType &&pair)
Definition: 30-visit.cpp:112
constexpr bool is_pair_type_v
Definition: 31-visit.cpp:21
std::enable_if_t< is_pair_of_variant_v< remove_cv_ref_t< PairType > > > visit_variant(VisitorType &&visit, PairType &&vpr)
Definition: tpf_types.hpp:7740
std::remove_cv_t< std::remove_reference_t< Type > > remove_cv_ref_t
Remove const volatile reference from Type.
Definition: tpf_types.hpp:151
constexpr auto endl
Definition: tpf_output.hpp:973
static enable_if_variant_t< VariantType > visit_variant(VisitorType &&visitor, VariantType &&vt)
Definition: 30-visit.cpp:50
static enable_if_pair_t< PairType > visit_variant(VisitorType &&visitor, PairType &&pair)
Definition: 30-visit.cpp:72
static constexpr bool value
Definition: 31-visit.cpp:11
static constexpr bool value
Definition: 31-visit.cpp:43
void for_each(ContainerType &&container)
Definition: 30-visit.cpp:136
std::tuple< VisitorTypes... > vistors_t
Definition: 31-visit.cpp:148
overloaded(VisitorTypes... visitors)
Definition: 30-visit.cpp:132
Stream output operators << are implemented.
#define Tpf_GetTypeCategory(instance_arg)
A macro that returns instance_arg's type category string name.
Definition: tpf_types.hpp:1428