C++ Library Extensions 2022.12.09
To help learn modern C++ programming
29-visit.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2
5
6namespace tpf::types
7{
8 template<size_t StartIndex, size_t EndIndex>
9 struct compile_time_loop
10 {
11 template<typename VisitorType, typename VariantType>
12 static void visit_variant(VisitorType&& visitor, VariantType&& vt)
13 {
14 if constexpr(StartIndex < EndIndex)
15 {
16 if(auto ptr = std::get_if<StartIndex>(&vt))
17 {
18 // auto& visit = std::get<StartIndex>(visitor.m_visitors); visit(*ptr);
19 std::get<StartIndex>(visitor.m_visitors)(*ptr);
20 return;
21 }
22 }
23
24 if constexpr (StartIndex + 1 < EndIndex)
25 {
27 visit_variant(std::forward<VisitorType>(visitor) , std::forward<VariantType>(vt));
28 }
29 }
30
31 }; // end of struct compile_time_loop
32
33 template<typename VisitorType, typename VariantType>
34 void visit(VisitorType&& visitor, VariantType&& vt)
35 {
36 using variant_t = remove_cv_ref_t<VariantType>;
37 // cppreference.com - std::variant_size_v
38 // https://en.cppreference.com/w/cpp/utility/variant/variant_size
39 constexpr size_t VariantSize = std::variant_size_v<variant_t>;
40
41 compile_time_loop<0, VariantSize>:: template
42 visit_variant(std::forward<VisitorType>(visitor), std::forward<VariantType>(vt));
43 }
44
45 template<typename... VisitorTypes>
46 struct overloaded
47 {
48 using vistors_t = std::tuple<VisitorTypes...>;
49
51
52 overloaded(VisitorTypes... visitors):
53 m_visitors{ std::move(visitors)...} { }
54
55 template<typename ContainerType>
56 void for_each(ContainerType&& container)
57 {
58 for(decltype(auto) vt:
59 std::forward<ContainerType>(container))
60 {
61 types::visit(*this, vt);
62 }
63 }
64 };
65
66 // template argument deduction guide
67 // this feature was introduced to C++17 Standards
68 template<typename... VisitorTypes>
69 overloaded(VisitorTypes...) -> overloaded<VisitorTypes...>;
70
71} // end of namespace tpf::types
72
73namespace types = tpf::types;
74
76{
77 using name_t = const char*;
78 using age_t = int;
79 using weight_t = double;
80 using variant_t = std::variant<name_t, age_t, weight_t>;
81
82 using container_t = std::vector<variant_t>;
83
84 container_t info;
85
86 info.emplace_back("Thomas Kim");
87 info.emplace_back(30);
88 info.emplace_back(60.5);
89 info.emplace_back("Sophie Turner");
90 info.emplace_back(20);
91 info.emplace_back(56.7);
92
94 auto endl = tpf::endl;
95
96 // we now have to concern about
97 // the order of the lambda functions
98 types::overloaded handle_info_auto_ref
99 {
100 [&stream, &endl](auto& name)
101 {
102 stream <<"Name is " << name << endl;
103 },
104
105 [&stream, &endl](auto& age)
106 {
107 stream <<"Age is " << age << endl;
108 },
109
110 [&stream, &endl](auto& weight)
111 {
112 stream << "Weight is " << weight << endl;
113 }
114 };
115
116 types::overloaded handle_info_const_auto_ref
117 {
118 [&stream, &endl](const auto& name)
119 {
120 stream <<"Name is " << name << endl;
121 },
122
123 [&stream, &endl](const auto& age)
124 {
125 stream <<"Age is " << age << endl;
126 },
127
128 [&stream, &endl](const auto& weight)
129 {
130 stream << "Weight is " << weight << endl;
131 }
132 };
133
134 for(const auto& vt: info)
135 {
136 types::visit(handle_info_const_auto_ref, vt);
137 }
138
139 stream << endl;
140
141 for(auto& vt: info)
142 {
143 types::visit(handle_info_auto_ref, vt);
144 }
145
146 stream << endl;
147}
148
150{
151 using name_t = const char*;
152 using age_t = int;
153 using weight_t = double;
154 using variant_t = std::variant<name_t, age_t, weight_t>;
155
156 using container_t = std::vector<variant_t>;
157
158 container_t info;
159
160 info.emplace_back("Thomas Kim");
161 info.emplace_back(30);
162 info.emplace_back(60.5);
163 info.emplace_back("Sophie Turner");
164 info.emplace_back(20);
165 info.emplace_back(56.7);
166
168 auto endl = tpf::endl;
169
170 // we now have to concern about
171 // the order of the lambda functions
172 types::overloaded handle_info
173 {
174 [&stream, &endl](auto&& name)
175 {
176 stream <<"Name is " << name << endl;
177 stream <<"Type: " << Tpf_GetTypeCategory(name) << endl;
178 },
179
180 [&stream, &endl](auto&& age)
181 {
182 stream <<"Age is " << age << endl;
183 stream <<"Type: " << Tpf_GetTypeCategory(age) << endl;
184 },
185
186 [&stream, &endl](auto&& weight)
187 {
188 stream << "Weight is " << weight << endl;
189 stream <<"Type: " << Tpf_GetTypeCategory(weight) << endl;
190 }
191 };
192
193
194 handle_info.for_each(info);
195
196 stream << endl;
197}
198
200{
201 using name_t = const char*;
202 using age_t = int;
203 using weight_t = double;
204 using variant_t = std::variant<name_t, age_t, weight_t>;
205
206 using container_t = std::set<variant_t>;
207
208 container_t info;
209
210 info.emplace("Thomas Kim");
211 info.emplace(30);
212 info.emplace(60.5);
213 info.emplace("Sophie Turner");
214 info.emplace(20);
215 info.emplace(56.7);
216
218 auto endl = tpf::endl;
219
220 // we now have to concern about
221 // the order of the lambda functions
222 types::overloaded handle_info
223 {
224 [&stream, &endl](auto&& name)
225 {
226 stream <<"Name is " << name << endl;
227 stream <<"Type: " << Tpf_GetTypeCategory(name) << endl;
228 },
229
230 [&stream, &endl](auto&& age)
231 {
232 stream <<"Age is " << age << endl;
233 stream <<"Type: " << Tpf_GetTypeCategory(age) << endl;
234 },
235
236 [&stream, &endl](auto&& weight)
237 {
238 stream << "Weight is " << weight << endl;
239 stream <<"Type: " << Tpf_GetTypeCategory(weight) << endl;
240 }
241 };
242
243 handle_info.for_each(info);
244
245 stream << endl;
246
247 // C++2a Standard: Fundamentals of C++ Template Metaprogramming 1/N (039)
248 // https://www.youtube.com/watch?v=nJuXE4VEYLI&t=237s
249 handle_info.for_each( types::reverse(info) );
250
251 stream << endl;
252
253}
254
256{
257 using key_t = const char*;
258 using name_t = const char*;
259 using age_t = int;
260 using weight_t = double;
261 using variant_t = std::variant<name_t, age_t, weight_t>;
262
263 using container_t = std::map<key_t, variant_t>;
264
265 container_t info;
266
267 info["Programmer"] = "Thomas Kim";
268 info["Age"] = 30;
269 info["Weight"] = 60.5;
270 info["Actress"] = "Sophie Turner";
271 info["Her age"] = 20;
272 info["Her weight"] = 56.7;
273
275 auto endl = tpf::endl;
276
277 // we now have to concern about
278 // the order of the lambda functions
279 types::overloaded handle_info
280 {
281 [&stream, &endl](auto&& name)
282 {
283 stream <<"Name is " << name << endl;
284 stream <<"Type: " << Tpf_GetTypeCategory(name) << endl;
285 },
286
287 [&stream, &endl](auto&& age)
288 {
289 stream <<"Age is " << age << endl;
290 stream <<"Type: " << Tpf_GetTypeCategory(age) << endl;
291 },
292
293 [&stream, &endl](auto&& weight)
294 {
295 stream << "Weight is " << weight << endl;
296 stream <<"Type: " << Tpf_GetTypeCategory(weight) << endl;
297 }
298 };
299
300 // handle_info.for_each(info);
301
302 for(auto& p: info)
303 {
304 auto& [key, vt] = p; // p is an element of std::map<key_t, variant_t>
305 // p is std::pair<const key_t, variant_t>
306
307 types::visit(handle_info, vt);
308 }
309
310 stream << endl;
311}
312
313int main()
314{
315 // stream <<"container vector " << endl;
316 // test_visit_simplified();
317
318 // stream <<"\ncontainer set " << endl;
320
321 // test_visit_simplified_map();
322}
void test_visit_basic()
Definition: 29-visit.cpp:75
void test_visit_simplified_map()
Definition: 29-visit.cpp:255
tpf::sstream stream
Definition: 29-visit.cpp:3
auto endl
Definition: 29-visit.cpp:4
void test_visit_simplified()
Definition: 29-visit.cpp:149
void test_visit_simplified_set()
Definition: 29-visit.cpp:199
int main()
Definition: 29-visit.cpp:313
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
enable_if_variant_t< VariantType > visit(VisitorType &&visitor, VariantType &&vt)
Definition: 31-visit.cpp:118
overloaded(VisitorTypes...) -> overloaded< VisitorTypes... >
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 void visit_variant(VisitorType &&visitor, VariantType &&vt)
Definition: 29-visit.cpp:12
static enable_if_variant_t< VariantType > visit_variant(VisitorType &&visitor, VariantType &&vt)
Definition: 31-visit.cpp:70
void for_each(ContainerType &&container)
Definition: 29-visit.cpp:56
std::tuple< VisitorTypes... > vistors_t
Definition: 31-visit.cpp:148
overloaded(VisitorTypes... visitors)
Definition: 29-visit.cpp:52
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