C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_any.hpp
Go to the documentation of this file.
1
12#ifndef _TPF_ANY_HPP
13#define _TPF_ANY_HPP
14
15#ifndef NOMINMAX
16#define NOMINMAX
17#endif
18
19#ifdef _MSVC_LANG
20 #if _MSVC_LANG < 201703L
21 #error This libary requires C++17 Standard (Visual Studio 2017).
22 #endif
23#else
24
25 #if __cplusplus < 201703
26 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
27 #endif // end of __cplusplus
28
29#endif // end of _MSVC_LANG
30
31#include <tpf_types.hpp>
32
33namespace tpf::types
34{
35 // forward declaration
36 template<typename... ElementTypes> class any;
37
38 namespace hidden
39 {
40 template<typename T>
42 {
43 static constexpr bool value = false;
44 };
45
46 template<typename... Types>
47 struct st_is_constrained_any< types::any<Types...> >
48 {
49 static constexpr bool value = true;
50 };
51
52 } // end of namespace hidden
53
54 template<typename T>
56
57 template<typename T>
58 constexpr bool is_special_type_v = is_constrained_any_v<T> || is_variant_v<T> || types::is_tuple_v<T>;
59
60 template<auto N, typename TypeAny>
62
63 template<typename... ElementTypes>
64 class any
65 {
66 public:
67 using element_types_t = unique_types_t<ElementTypes...>;
68
70
71 static constexpr auto param_count
72 = type_count_v<element_types_t>;
73
76
79
81
82 protected:
83 std::any m_any;
84
85 int m_dummy{};
86 public:
87
88 any(): m_any{} { }
89
90 bool has_value() const noexcept
91 {
92 return this->m_any.has_value();
93 }
94
95 void reset() noexcept
96 {
97 this->m_any.reset();
98 }
99
100 void swap(any& other) noexcept
101 {
102 this->m_any.swap(other);
103 }
104
105 const std::type_info& type() const noexcept
106 {
107 return this->m_any.type();
108 }
109
110 template< class ValueType, class... Args,
111 typename = std::enable_if_t< std::is_constructible_v<ValueType, remove_cv_ref_t<Args>...>>>
113 emplace( Args&&... args )
114 {
115 return this->m_any. template emplace<ValueType>(std::forward<Args>(args)...);
116 }
117
118 template< class ValueType, class U, class... Args >
120 emplace( std::initializer_list<U> il, Args&&... args )
121 {
122 return this->m_any. template emplace<ValueType>( il, std::forward<Args>(args)...);
123 }
124
125 std::string current_type() const noexcept;
126
127 std::any& std() noexcept { return m_any; }
128 const std::any& std() const noexcept { return m_any; }
129
130 constexpr auto allowed_types() const noexcept
131 { return element_types_t{}; }
132
133 variant_t to_variant() const noexcept;
134
135 // if Type is not in the list, element_types_t,
136 // this constructor is disabled
137 template<typename Type,
139 any(Type&& arg): m_any{ std::forward<Type>(arg) } { }
140
141 any(const any&) = default;
142 any(any&& rhs) = default;
143
144 any& operator=(const any&) = default;
145 any& operator=(any&&) = default;
146
147 // value assignment operator
148 template<typename Type,
150 any& operator=(Type&& arg)
151 {
152 this->m_any = std::forward<Type>(arg);
153 return *this;
154 }
155
156 any& operator=(const std::variant<ElementTypes...>& v)
157 {
158 constexpr size_t Size = sizeof...(ElementTypes);
159
160 try
161 {
162 types::for_workhorse<Size>([&](auto index)
163 {
164 if(auto pval = std::get_if<index.Index>(&v))
165 {
166 this->m_any = *pval;
167 throw 1; //exit loop
168 }
169 });
170
171 }catch(...) { }
172
173 return *this;
174 }
175
177 template<typename Type,
180 {
181 // https://en.cppreference.com/w/cpp/utility/any/any_cast
182 if constexpr(std::is_pointer_v<remove_cv_ref_t<Type>>)
183 return std::any_cast<std::remove_pointer_t<Type>>(&this->m_any);
184 else
185 return std::any_cast<Type>(this->m_any);
186 }
187
188 template<typename Type,
190 Type get() const
191 {
192 // https://en.cppreference.com/w/cpp/utility/any/any_cast
193 if constexpr(std::is_pointer_v<remove_cv_ref_t<Type>>)
194 return std::any_cast<std::remove_pointer_t<Type>>(&this->m_any);
195 else
196 return std::any_cast<Type>(this->m_any);
197 }
198
199 template<typename Type,
201 operator Type&()
202 {
203 return this->get<Type&>();
204 }
205
206 template<typename Type,
208 operator const Type&() const
209 {
210 return this->get<const Type&>();
211 }
212
213 template<typename CurrentType, typename CallbackType, typename... ArgTypes,
215 bool if_any_type(CallbackType&& callback, ArgTypes&&... args)
216 {
217 if(auto ptr = std::any_cast<CurrentType>(&this->m_any))
218 {
219 callback(*ptr, std::forward<ArgTypes>(args)...); return true;
220 }
221 else return false;
222 }
223
224 template<typename CurrentType, typename CallbackType, typename... ArgTypes,
226 bool if_any_type(CallbackType&& callback, ArgTypes&&... args) const
227 {
228 if(auto ptr = std::any_cast<CurrentType>(&this->m_any))
229 {
230 callback(*ptr, std::forward<ArgTypes>(args)...); return true;
231 }
232 else return false;
233 }
234
235 template<auto TypeIndex, typename CallbackType, typename... ArgTypes,
236 typename any_type = types::any<ElementTypes...>,
237 typename element_types = typename any_type::element_types_t,
238 typename CurrentType = select_nth_type_t<TypeIndex, element_types>,
240 void if_any_index(CallbackType&& callback, ArgTypes&&... args)
241 {
242 if(auto ptr = std::any_cast<CurrentType>(&this->m_any))
243 callback(*ptr, std::forward<ArgTypes>(args)...);
244 }
245
246 template<auto TypeIndex, typename CallbackType, typename... ArgTypes,
247 typename any_type = types::any<ElementTypes...>,
248 typename element_types = typename any_type::element_types_t,
249 typename CurrentType = select_nth_type_t<TypeIndex, element_types>,
251 bool if_any_index(CallbackType&& callback, ArgTypes&&... args) const
252 {
253 if(auto ptr = std::any_cast<CurrentType>(&this->m_any))
254 callback(*ptr, std::forward<ArgTypes>(args)...);
255 }
256
257 virtual ~any() { }
258
260 template<typename Type,
262 any& operator+=(Type&& arg)
263 {
265 this->get<type&>() += std::forward<Type>(arg);
266 return *this;
267 }
268
269 template<typename Type,
271 any& operator-=(Type&& arg)
272 {
274 this->get<type&>() -= std::forward<Type>(arg);
275 return *this;
276 }
277
278 template<typename Type,
280 any& operator*=(Type&& arg)
281 {
283 this->get<type&>() *= std::forward<Type>(arg);
284 return *this;
285 }
286
287 template<typename Type,
289 any& operator/=(Type&& arg)
290 {
292 this->get<type&>() /= std::forward<Type>(arg);
293 return *this;
294 }
295
296 // template<typename CharType>
297 // friend std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& os, const any& a)
298 // {
299 // if(!a.std().has_value())
300 // {
301 // os << "no_value"; return os;
302 // }
303 // else
304 // {
305 // constexpr int Size = sizeof...(ElementTypes);
306
307 // try
308 // {
309 // types::for_workhorse<Size>([&os, &a](auto i)
310 // {
311 // using element_types_t = typename any::element_types_t;
312
313 // using element_t = select_nth_type_t<i.Index, element_types_t>;
314
315 // if(auto ptr = std::any_cast<element_t>(&a.std()))
316 // {
317 // os << *ptr;
318
319 // // operation successful
320 // throw types::no_type_t{};
321 // }
322 // });
323
324 // }catch(const types::no_type_t&) { }
325
326 // return os;
327 // }
328 // }
329
330 }; // end of class any
331
332 template<typename... CallbackTypes>
333 struct any_visitors: public CallbackTypes...
334 {
335 using CallbackTypes::operator()...;
336
338
339 public:
340
342 template<typename Type, typename AnyType, typename... ArgTypes>
343 std::enable_if_t<is_any_v<remove_cv_ref_t<AnyType>>, bool>
344 if_any_type(AnyType&& any, ArgTypes&&... args) const
345 {
346 if(auto ptr = std::any_cast<Type>(&any))
347 {
348 this->operator()(*ptr, std::forward<ArgTypes>(args)...);
349 return true;
350 }
351 else return false;
352 }
353
355 template<typename Type, typename AnyType, typename... ArgTypes>
356 std::enable_if_t<is_constrained_any_v<remove_cv_ref_t<AnyType>>, bool>
357 if_any_type(AnyType&& any, ArgTypes&&... args) const
358 {
359 if(auto ptr = std::any_cast<Type>(&any.std()))
360 {
361 this->operator()(*ptr, std::forward<ArgTypes>(args)...); return true;
362 }
363 else return false;
364 }
365
366 template<typename AnyType, typename... ArgTypes,
367 typename any_type = remove_cv_ref_t<AnyType>,
368 typename = std::enable_if_t<is_constrained_any_v<any_type>>,
370 void apply(AnyType&& any, ArgTypes&&... args) const;
371
372 template<typename Type, typename... Types, typename... ArgTypes, typename AnyType,
373 typename any_type = remove_cv_ref_t<AnyType>,
374 typename = std::enable_if_t<is_any_v<any_type> || is_constrained_any_v<any_type>>,
376 void apply(AnyType&& any, ArgTypes&&... args) const;
377
378 template<typename ContainerType, typename... ArgTypes>
379 void visit(ContainerType&& container, ArgTypes&&... args) const
380 {
381 for(auto& a: container) this->template apply(a, std::forward<ArgTypes>(args)...);
382 }
383
384 template<typename ContainerType, typename... ArgTypes>
385 void visit_with_index(ContainerType&& container, ArgTypes&&... args) const
386 {
387 for(int i = 0; i < (int)container.size(); ++i)
388 this->template apply(container[i], i, std::forward<ArgTypes>(args)...);
389 }
390
391 template<typename Type, typename ContainerType, typename... ArgTypes>
392 void visit_if_any_type(ContainerType&& container, ArgTypes&& ... args) const
393 {
394 for(auto& a: container)
395 this->template if_any_type<Type>(a, std::forward<ArgTypes>(args)... );
396 }
397
398 template<typename Type, typename ContainerType, typename... ArgTypes>
399 void visit_if_any_type_with_index(ContainerType&& container, ArgTypes&&... args) const
400 {
401 for(int i = 0; i < (int)container.size(); ++i)
402 this->template if_any_type<Type>(container[i], i, std::forward<ArgTypes>(args)... );
403 }
404 };
405
406 template<typename... CallbackTypes>
407 any_visitors(CallbackTypes...)->any_visitors<CallbackTypes...>;
408
409 template<typename Type, typename... Types>
411 {
412 template<typename AnyType>
413 static std::enable_if_t<is_constrained_any_v<remove_cv_ref_t<AnyType>>, std::string>
414 current_type(AnyType&& a)
415 {
416 if(auto ptr = std::any_cast<Type>(&a.std()))
417 return Tpf_GetTypeName(Type);
418 else
419 {
420 if constexpr(sizeof...(Types) != 0)
422 else // this part never really executed
423 return "To suppress syntax error";
424 }
425 }
426
427 template<typename VariantType, typename AnyType>
428 static void variant_to_any(const VariantType& var, AnyType& any)
429 {
430 if(auto ptr = std::get_if<Type>(&var))
431 any = *ptr;
432 else
433 {
434 if constexpr(sizeof...(Types) != 0)
436 }
437 }
438
439 template<typename AnyType, typename VariantType>
440 static void any_to_variant(const AnyType& any, VariantType& var)
441 {
442 if(auto ptr = std::any_cast<Type>(&any))
443 var = *ptr;
444 else
445 {
446 if constexpr(sizeof...(Types) != 0)
448 }
449 }
450 };
451
452 template<typename Type, typename... Types>
453 struct st_process_any<type_list_t<Type, Types...>>
454 {
455 template<typename AnyType, typename Visitors>
456 static void visit_any(Visitors&& visitors, AnyType&& a)
457 {
458 if(auto ptr = std::any_cast<Type>(&a.std()))
459 visitors(*ptr);
460 else
461 {
462 if constexpr(sizeof...(Types) != 0)
464 visit_any(visitors, std::forward<AnyType>(a));
465 }
466 }
467
468 template<typename Visitors, typename AnyType, typename... ArgTypes>
469 static void apply_to_any(Visitors&& visitor, AnyType&& any, ArgTypes&&... args)
470 {
471 if constexpr(types::is_type_list_v<Type>)
472 st_process_any<Type>::apply_to_any(visitor, any, std::forward<ArgTypes>(args)...);
473 else
474 visitor.template apply<Type, Types...>(any, std::forward<ArgTypes>(args)...);
475 }
476
477 template<typename AnyType, typename VariantType>
478 static void any_to_variant(const AnyType& any, VariantType& var)
479 {
481 }
482 };
483
484 template<typename Type, typename... Types>
485 any<Type, Types...> variant_to_any(const std::variant<Type, Types...>& var)
486 {
487 using any_t = any<Type, Types...>; any_t any;
489
490 return any;
491 }
492
493 template<typename Type, typename... Types>
494 std::any variant_to_std_any(const std::variant<Type, Types...>& var)
495 {
496 using any_t = std::any; any_t any;
498
499 return any;
500 }
501
502 template<typename... ElementTypes>
503 typename any<ElementTypes...>::variant_t
505 {
506 variant_t var;
507
508 if(!this->has_value()) return var;
509 else
510 {
512 return var;
513 }
514 }
515
516 template<typename... CallbackTypes>
517 template<typename Type, typename... Types, typename... ArgTypes,
518 typename AnyType, typename any_type, typename, typename arg_list_t>
519 void any_visitors<CallbackTypes...>::apply(AnyType&& any, ArgTypes&&... args) const
520 {
521 if constexpr(is_constrained_any_v<AnyType>)
522 this->apply<Type, Types...>(any.std(), std::forward<ArgTypes>(args)...);
523 else
524 {
525 if constexpr(is_type_list_v<Type>)
526 {
527 st_process_any<Type>::apply_to_any(*this, any, std::forward<ArgTypes>(args)...);
528
529 if constexpr(sizeof...(Types) != 0)
530 this->apply<Types...>(any, std::forward<ArgTypes>(args)...);
531 }
532 else
533 {
534 if(!this->template if_any_type<Type>(any, std::forward<ArgTypes>(args)...))
535 {
536 if constexpr(sizeof...(Types) != 0)
537 this->apply<Types...>(any, std::forward<ArgTypes>(args)...);
538 else
539 {
540 if(this->report_unhandled_value && any.has_value())
541 {
542 throw std::runtime_error("WARNING - Any has value but not handled");
543 }
544 }
545 }
546 }
547 }
548 }
549
550 template<typename... CallbackTypes>
551 template<typename AnyType, typename... ArgTypes, typename any_type, typename, typename arg_list_t>
552 void any_visitors<CallbackTypes...>::apply(AnyType&& any, ArgTypes&&... args) const
553 {
554 using any_t = remove_cv_ref_t<AnyType>;
555 using element_types = typename any_t::element_types_t;
556
557 st_process_any<element_types>::apply_to_any(*this, any.std(), std::forward<ArgTypes>(args)...);
558 }
559
560 template<typename... ElementTypes>
561 std::string current_type(const any<ElementTypes...>& a)
562 {
564 }
565
566 template<typename... ElementTypes>
567 std::string any<ElementTypes...>::current_type() const noexcept
568 {
570 }
571
572 template<typename Visitors, typename AnyType, typename... ArgTypes>
573 void visit_any(Visitors&& visitors, AnyType&& a, ArgTypes&&... args)
574 {
575 using any_t = remove_cv_ref_t<AnyType>;
576
578 apply_to_any(visitors, std::forward<AnyType>(a), std::forward<ArgTypes>(args)...);
579 }
580
581 template<typename CurrentType, typename AnyType, typename Handler,
582 typename = std::enable_if<std::is_same_v<remove_cv_ref_t<AnyType>, std::any>>>
583 void if_any_type(AnyType&& a, Handler&& handler)
584 {
585 if(auto ptr = std::any_cast<CurrentType>(&a)) handler(*ptr);
586 }
587
588} // end of namespace tpf::types
589
590#endif // end of file _TPF_ANY_HPP
const std::any & std() const noexcept
Definition: tpf_any.hpp:128
union_type_t< element_types_t, pointer_types_t > element_pointer_types_t
Definition: tpf_any.hpp:78
std::string current_type() const noexcept
Definition: tpf_any.hpp:567
any & operator=(Type &&arg)
Definition: tpf_any.hpp:150
any & operator+=(Type &&arg)
Definition: tpf_any.hpp:262
Type get() const
Definition: tpf_any.hpp:190
void reset() noexcept
Definition: tpf_any.hpp:95
any & operator=(any &&)=default
types::to_variant_t< element_types_t > variant_t
Definition: tpf_any.hpp:69
unique_types_t< std::add_pointer_t< ElementTypes >... > pointer_types_t
Definition: tpf_any.hpp:75
void swap(any &other) noexcept
Definition: tpf_any.hpp:100
types::index_tuple_vector_t< param_count > index_vector_t
Definition: tpf_any.hpp:80
virtual ~any()
Definition: tpf_any.hpp:257
any & operator*=(Type &&arg)
Definition: tpf_any.hpp:280
std::any m_any
Definition: tpf_any.hpp:83
bool has_value() const noexcept
Definition: tpf_any.hpp:90
any & operator=(const std::variant< ElementTypes... > &v)
Definition: tpf_any.hpp:156
any & operator/=(Type &&arg)
Definition: tpf_any.hpp:289
constexpr auto allowed_types() const noexcept
Definition: tpf_any.hpp:130
variant_t to_variant() const noexcept
Definition: tpf_any.hpp:504
any & operator=(const any &)=default
any & operator-=(Type &&arg)
Definition: tpf_any.hpp:271
any(any &&rhs)=default
void if_any_index(CallbackType &&callback, ArgTypes &&... args)
Definition: tpf_any.hpp:240
static constexpr auto param_count
Definition: tpf_any.hpp:72
any(const any &)=default
enable_if_in_list_t< ValueType, element_types_t, std::decay_t< ValueType > & > emplace(std::initializer_list< U > il, Args &&... args)
Definition: tpf_any.hpp:120
std::any & std() noexcept
Definition: tpf_any.hpp:127
enable_if_in_list_t< ValueType, element_types_t, std::decay_t< ValueType > & > emplace(Args &&... args)
Definition: tpf_any.hpp:113
bool if_any_type(CallbackType &&callback, ArgTypes &&... args)
Definition: tpf_any.hpp:215
bool if_any_index(CallbackType &&callback, ArgTypes &&... args) const
Definition: tpf_any.hpp:251
const std::type_info & type() const noexcept
Definition: tpf_any.hpp:105
unique_types_t< ElementTypes... > element_types_t
Definition: tpf_any.hpp:67
bool if_any_type(CallbackType &&callback, ArgTypes &&... args) const
Definition: tpf_any.hpp:226
constexpr decltype(auto) apply(F &&f, T(&&c_array)[N])
Type to string name conversions are defined.
Definition: 31-visit.cpp:7
hidden::enable_if_in_list_t< TestType, TypeList, ReturnType > enable_if_in_list_t
Definition: tpf_types.hpp:6406
any_visitors(CallbackTypes...) -> any_visitors< CallbackTypes... >
void if_any_type(AnyType &&a, Handler &&handler)
Definition: tpf_any.hpp:583
hidden::unique_types_t< Types... > unique_types_t
Definition: tpf_types.hpp:5627
hidden::union_type_t< unique_types_t< LeftList >, unique_types_t< RightList > > union_type_t
Definition: tpf_types.hpp:5651
constexpr bool is_special_type_v
Definition: tpf_any.hpp:58
std::string current_type(const any< ElementTypes... > &a)
Definition: tpf_any.hpp:561
any< Type, Types... > variant_to_any(const std::variant< Type, Types... > &var)
Definition: tpf_any.hpp:485
constexpr bool is_constrained_any_v
Definition: tpf_any.hpp:55
typename hidden::st_index_tuple_vector< std::make_index_sequence< N > >::type index_tuple_vector_t
Definition: tpf_types.hpp:1211
hidden::to_variant_t< Type, Types... > to_variant_t
Definition: tpf_types.hpp:5630
select_nth_type_t< N, typename TypeAny::element_types_t > any_element_t
Definition: tpf_any.hpp:61
hidden::select_nth_type_t< SelectIndex, Types... > select_nth_type_t
Definition: tpf_types.hpp:5585
void visit_any(Visitors &&visitors, AnyType &&a, ArgTypes &&... args)
Definition: tpf_any.hpp:573
typename hidden::st_build_arg_types< Heads, Tails >::type arg_list_t
Definition: tpf_types.hpp:6155
std::any variant_to_std_any(const std::variant< Type, Types... > &var)
Definition: tpf_any.hpp:494
std::remove_cv_t< std::remove_reference_t< Type > > remove_cv_ref_t
Remove const volatile reference from Type.
Definition: tpf_types.hpp:151
std::remove_cv_t< std::remove_reference_t< std::decay_t< Type > > > decay_remove_cv_ref_t
Decay, remove const, volatile, reference.
Definition: tpf_types.hpp:162
void visit_with_index(ContainerType &&container, ArgTypes &&... args) const
Definition: tpf_any.hpp:385
void visit(ContainerType &&container, ArgTypes &&... args) const
Definition: tpf_any.hpp:379
void visit_if_any_type(ContainerType &&container, ArgTypes &&... args) const
Definition: tpf_any.hpp:392
std::enable_if_t< is_constrained_any_v< remove_cv_ref_t< AnyType > >, bool > if_any_type(AnyType &&any, ArgTypes &&... args) const
returns true if successful, otherwise false
Definition: tpf_any.hpp:357
std::enable_if_t< is_any_v< remove_cv_ref_t< AnyType > >, bool > if_any_type(AnyType &&any, ArgTypes &&... args) const
returns true if successful, otherwise false
Definition: tpf_any.hpp:344
void visit_if_any_type_with_index(ContainerType &&container, ArgTypes &&... args) const
Definition: tpf_any.hpp:399
void apply(AnyType &&any, ArgTypes &&... args) const
Definition: tpf_any.hpp:552
static void apply_to_any(Visitors &&visitor, AnyType &&any, ArgTypes &&... args)
Definition: tpf_any.hpp:469
static void any_to_variant(const AnyType &any, VariantType &var)
Definition: tpf_any.hpp:478
static void visit_any(Visitors &&visitors, AnyType &&a)
Definition: tpf_any.hpp:456
static std::enable_if_t< is_constrained_any_v< remove_cv_ref_t< AnyType > >, std::string > current_type(AnyType &&a)
Definition: tpf_any.hpp:414
static void any_to_variant(const AnyType &any, VariantType &var)
Definition: tpf_any.hpp:440
static void variant_to_any(const VariantType &var, AnyType &any)
Definition: tpf_any.hpp:428
This type is used to manipulate type list.
Definition: tpf_types.hpp:956
Type functions are implemented.
#define Tpf_GetTypeName(type_arg)
A macro that returns type_arg's string name.
Definition: tpf_types.hpp:1422