refl-cpp
refl.hpp
Go to the documentation of this file.
1 // The MIT License (MIT)
2 //
3 // Copyright (c) 2020 Veselin Karaganev (@veselink1) and Contributors
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #ifndef REFL_INCLUDE_HPP
24 #define REFL_INCLUDE_HPP
25 
26 #include <stddef.h> // size_t
27 #include <cstring>
28 #include <array>
29 #include <utility> // std::move, std::forward
30 #include <optional>
31 #include <tuple>
32 #include <type_traits>
33 #include <ostream>
34 #include <sstream>
35 #include <iomanip> // std::quoted
36 
37 namespace std
38 {
39  template <typename T, typename Deleter>
40  class unique_ptr;
41 
42  template <typename T>
43  class shared_ptr;
44 
45  template <typename T>
46  class weak_ptr;
47 
48  template <typename T>
49  class complex;
50 } // namespace std
51 
52 #ifdef _MSC_VER
53 // Disable VS warning for "Not enough arguments for macro"
54 // (emitted when a REFL_ macro is not provided any attributes)
55 #pragma warning( disable : 4003 )
56 #endif
57 
58 #if defined(__clang__)
59  #if __has_feature(cxx_rtti)
60  #define REFL_RTTI_ENABLED
61  #endif
62 #elif defined(__GNUG__)
63  #if defined(__GXX_RTTI)
64  #define REFL_RTTI_ENABLED
65  #endif
66 #elif defined(_MSC_VER)
67  #if defined(_CPPRTTI)
68  #define REFL_RTTI_ENABLED
69  #endif
70 #endif
71 
72 /**
73  * @brief The top-level refl-cpp namespace
74  * It contains a few core refl-cpp namespaces and directly exposes core classes and functions.
75  * <ul>
76  * <li>util - utility functions (for_each, map_to_tuple, etc.)</li>
77  * <li>trait - type-traits and other operations on types (is_function_v, map_t, etc.)</li>
78  * <li>runtime - utility functions and classes that always have a runtime overhead (proxy<T>, debug_str, etc.)</li>
79  * <li>member - contains the empty classes member and function (used for tagging)</li>
80  * <li>descriptor - contains the non-specialized member types (type|field_descriptor<T, N>, and operations on them (get_property, get_display_name, etc.))</li>
81  * </ul>
82  *
83  * using util::type_list; <br>
84  * using descriptor::type_descriptor; <br>
85  * using descriptor::field_descriptor; <br>
86  * using descriptor::function_descriptor; <br>
87  * using util::const_string; <br>
88  * using util::make_const_string; <br>
89  */
90 namespace refl
91 {
92  /**
93  * @brief Contains utility types and functions for working with those types.
94  */
95  namespace util
96  {
97  /**
98  * Converts a compile-time available const char* value to a const_string<N>.
99  * The argument must be a *core constant expression* and be null-terminated.
100  *
101  * @see refl::util::const_string
102  */
103 #define REFL_MAKE_CONST_STRING(CString)
104  (::refl::util::detail::copy_from_unsized<::refl::util::detail::strlen(CString)>(CString))
105 
106  /**
107  * Represents a compile-time string. Used in refl-cpp
108  * for representing names of reflected types and members.
109  * Supports constexpr concatenation and substring,
110  * and is explicitly-convertible to const char* and std::string.
111  * REFL_MAKE_CONST_STRING can be used to create an instance from a literal string.
112  *
113  * @typeparam <N> The length of the string excluding the terminating '\0' character.
114  * @see refl::descriptor::base_member_descriptor::name
115  */
116  template <size_t N>
118  {
119  /** The largest positive value size_t can hold. */
120  static constexpr size_t npos = static_cast<size_t>(-1);
121 
122  /** The length of the string excluding the terminating '\0' character. */
123  static constexpr size_t size = N;
124 
125  /**
126  * The statically-sized character buffer used for storing the string.
127  */
128  char data[N + 1];
129 
130  /**
131  * Creates an empty const_string.
132  */
133  constexpr const_string() noexcept
134  : data{}
135  {
136  }
137 
138  /**
139  * Creates a copy of a const_string.
140  */
141  constexpr const_string(const const_string<N>& other) noexcept
142  : const_string(other, std::make_index_sequence<N>())
143  {
144  }
145 
146  /**
147  * Creates a const_string by copying the contents of data.
148  */
149  constexpr const_string(const char(&data)[N + 1]) noexcept
150  : const_string(data, std::make_index_sequence<N>())
151  {
152  }
153 
154  /**
155  * Explicitly converts to const char*.
156  */
157  explicit constexpr operator const char*() const noexcept
158  {
159  return data;
160  }
161 
162  /**
163  * Explicitly converts to std::string.
164  */
165  explicit operator std::string() const noexcept
166  {
167  return data;
168  }
169 
170  /**
171  * Returns a pointer to the contained zero-terminated string.
172  */
173  constexpr const char* c_str() const noexcept
174  {
175  return data;
176  }
177 
178  /**
179  * Returns the contained string as an std::string.
180  */
181  std::string str() const noexcept
182  {
183  return data;
184  }
185 
186  /**
187  * A constexpr version of std::string::substr.
188  *
189  * \code{.cpp}
190  * make_const_string("Hello, World!").template substr<0, 4>() -> (const_string<4>) "Hell"
191  * make_const_string("Hello, World!").template substr<1, 4>() -> (const_string<3>) "ell"
192  * \endcode
193  */
194  template <size_t Pos, size_t Count = npos>
195  constexpr auto substr() const noexcept
196  {
197  static_assert(Pos <= N);
198  constexpr size_t NewSize = std::min(Count, N - Pos);
199 
200  char buf[NewSize + 1]{};
201  for (size_t i = 0; i < NewSize; i++) {
202  buf[i] = data[Pos + i];
203  }
204 
205  return const_string<NewSize>(buf);
206  }
207 
208  /**
209  * Searches the string for the first occurrence of the character and returns its position.
210  *
211  * \code{.cpp}
212  * make_const_string("Hello, World!").find('e') -> 1
213  * make_const_string("Hello, World!").find('z') -> static_cast<size_t>(-1)
214  * \endcode
215  */
216  constexpr auto find(char ch, size_t pos = 0) const noexcept
217  {
218  for (size_t i = pos; i < N; i++) {
219  if (data[i] == ch) {
220  return i;
221  }
222  }
223  return npos;
224  }
225 
226  /**
227  * Searches the string for the last occurrence of the character and returns its position.
228  *
229  * \code{.cpp}
230  * make_const_string("Hello, World!").rfind('o') -> 8
231  * make_const_string("Hello, World!").rfind('z') -> static_cast<size_t>(-1)
232  * \endcode
233  */
234  constexpr auto rfind(char ch, size_t pos = npos) const noexcept
235  {
236  for (size_t i = (pos == npos ? N - 1 : pos); i + 1 > 0; i--) {
237  if (data[i] == ch) {
238  return i;
239  }
240  }
241  return npos;
242  }
243 
244  private:
245 
246  /**
247  * Creates a copy of a const_string.
248  */
249  template <size_t... Idx>
250  constexpr const_string(const const_string<N>& other, std::index_sequence<Idx...>) noexcept
251  : data{ other.data[Idx]... }
252  {
253  }
254 
255  /**
256  * Creates a const_string by copying the contents of data.
257  */
258  template <size_t... Idx>
259  constexpr const_string(const char(&data)[sizeof...(Idx) + 1], std::index_sequence<Idx...>) noexcept
260  : data{ data[Idx]... }
261  {
262  }
263 
264  };
265 
266  /**
267  * Creates an empty instance of const_string<N>
268  *
269  * @see refl::util::const_string
270  */
271  constexpr const_string<0> make_const_string() noexcept
272  {
273  return {};
274  }
275 
276  /**
277  * Creates an instance of const_string<N>
278  *
279  * @see refl::util::const_string
280  */
281  template <size_t N>
282  constexpr const_string<N - 1> make_const_string(const char(&str)[N]) noexcept
283  {
284  return str;
285  }
286 
287  /**
288  * Creates an instance of const_string<N>
289  *
290  * @see refl::util::const_string
291  */
292  constexpr const_string<1> make_const_string(char ch) noexcept
293  {
294  const char str[2]{ ch, '\0' };
295  return make_const_string(str);
296  }
297 
298  /**
299  * Concatenates two const_strings together.
300  *
301  * @see refl::util::const_string
302  */
303  template <size_t N, size_t M>
304  constexpr const_string<N + M> operator+(const const_string<N>& a, const const_string<M>& b) noexcept
305  {
306  char data[N + M + 1] { };
307  for (size_t i = 0; i < N; i++)
308  data[i] = a.data[i];
309  for (size_t i = 0; i < M; i++)
310  data[N + i] = b.data[i];
311  return data;
312  }
313 
314  /**
315  * Concatenates a const_string with a C-style string.
316  *
317  * @see refl::util::const_string
318  */
319  template <size_t N, size_t M>
320  constexpr const_string<N + M - 1> operator+(const const_string<N>& a, const char(&b)[M]) noexcept
321  {
322  return a + make_const_string(b);
323  }
324 
325  /**
326  * Concatenates a C-style string with a const_string.
327  *
328  * @see refl::util::const_string
329  */
330  template <size_t N, size_t M>
331  constexpr const_string<N + M - 1> operator+(const char(&a)[N], const const_string<M>& b) noexcept
332  {
333  return make_const_string(a) + b;
334  }
335 
336  /**
337  * Compares two const_strings for equality.
338  *
339  * @see refl::util::const_string
340  */
341  template <size_t N, size_t M>
342  constexpr bool operator==(const const_string<N>& a, const const_string<M>& b) noexcept
343  {
344  if constexpr (N != M) {
345  return false;
346  }
347  else {
348  for (size_t i = 0; i < M; i++) {
349  if (a.data[i] != b.data[i]) {
350  return false;
351  }
352  }
353  return true;
354  }
355  }
356 
357  /**
358  * Compares two const_strings for equality.
359  *
360  * @see refl::util::const_string
361  */
362  template <size_t N, size_t M>
363  constexpr bool operator!=(const const_string<N>& a, const const_string<M>& b) noexcept
364  {
365  return !(a == b);
366  }
367 
368  /**
369  * Compares a const_string with a C-style string for equality.
370  *
371  * @see refl::util::const_string
372  */
373  template <size_t N, size_t M>
374  constexpr bool operator==(const const_string<N>& a, const char(&b)[M]) noexcept
375  {
376  return a == make_const_string(b);
377  }
378 
379  /**
380  * Compares a const_string with a C-style string for equality.
381  *
382  * @see refl::util::const_string
383  */
384  template <size_t N, size_t M>
385  constexpr bool operator!=(const const_string<N>& a, const char(&b)[M]) noexcept
386  {
387  return a != make_const_string(b);
388  }
389 
390  /**
391  * Compares a C-style string with a const_string for equality.
392  *
393  * @see refl::util::const_string
394  */
395  template <size_t N, size_t M>
396  constexpr bool operator==(const char(&a)[N], const const_string<M>& b) noexcept
397  {
398  return make_const_string(a) == b;
399  }
400 
401  /**
402  * Compares a C-style string with a const_string for equality.
403  *
404  * @see refl::util::const_string
405  */
406  template <size_t N, size_t M>
407  constexpr bool operator!=(const char(&a)[N], const const_string<M>& b) noexcept
408  {
409  return make_const_string(a) != b;
410  }
411 
412  template <size_t N>
413  constexpr std::ostream& operator<<(std::ostream& os, const const_string<N>& str) noexcept
414  {
415  return os << str.c_str();
416  }
417 
418  namespace detail
419  {
420  constexpr size_t strlen(const char* const str)
421  {
422  return *str ? 1 + strlen(str + 1) : 0;
423  }
424 
425  template <size_t N>
426  constexpr const_string<N> copy_from_unsized(const char* const str)
427  {
428  const_string<N> cstr;
429  for (size_t i = 0; i < N; i++) {
430  cstr.data[i] = str[i];
431  }
432  return cstr;
433  }
434  } // namespace detail
435 
436  /**
437  * Represents a compile-time list of types provided as variadic template parameters.
438  * type_list is an empty TrivialType. Instances of it can freely be created to communicate
439  * the list of represented types. type_lists support many standard operations that are
440  * implicitly available with ADL-lookup. type_list is used by refl-cpp mostly to represent
441  * the list of refl::field_descriptor, refl::function_descriptor specializations that
442  * allow the compile-time reflection of a type's members.
443  *
444  * @see refl::util::for_each
445  * @see refl::util::map_to_array
446  * @see refl::util::map_to_tuple
447  * @see refl::member_list
448  *
449  * # Examples
450  * ```
451  * for_each(type_list<int, float>(), [](auto) { ... });
452  * ```
453  */
454  template <typename... Ts>
455  struct type_list
456  {
457  /** The number of types in this type_list */
458  static constexpr intptr_t size = sizeof...(Ts);
459  };
460 
461  template <typename T>
462  struct type_list<T>
463  {
464  typedef T type;
465  static constexpr intptr_t size = 1;
466  };
467 
468  template <typename T>
469  using type_tag = type_list<T>;
470 
471  } // namespace util
472 
473  using util::const_string;
474  using util::make_const_string;
475  using util::type_list;
476  using util::type_tag;
477 
478  /**
479  * The contents of the refl::detail::macro_exports namespace
480  * is implicitly available in the context of REFL_TYPE/FIELD/FUNC macros.
481  * It is used to export the refl::attr:: standard attributes.
482  */
483  namespace detail
484  {
485  namespace macro_exports
486  {
487  }
488  }
489 
490 } // namespace refl
491 
492 /**
493  * refl_impl is an internal namespace that should not be used by the users of refl-cpp.
494  */
495 namespace refl_impl
496 {
497  /**
498  * Contains the generated metadata types.
499  * (i.e. type_info__)
500  */
501  namespace metadata
502  {
503  // Import everyting from macro_exports here to make it visible in REFL_ macro context.
504  using namespace refl::detail::macro_exports;
505 
506  /**
507  * The core reflection metadata type.
508  * type_info__ holds data for a type T.
509  *
510  * The non-specialized type_info__ type has a member typedef invalid_marker
511  * that can be used to detect it.
512  *
513  * Specializations of this type should provide all members of this
514  * generic definition, except invalid_marker.
515  *
516  * @typeparam <T> The reflected type.
517  */
518  template <typename T>
519  struct type_info__
520  {
521  /** Used for detecting this non-specialized type_info__ instance. */
522  struct invalid_marker{};
523 
524  /**
525  * This is a placeholder definition of which no type instances should be created.
526  */
527  template <size_t, typename>
528  struct member;
529 
530  /** The number of reflected members of the target type T. */
531  static constexpr size_t member_count{ 0 };
532 
533  /** This is a placeholder definition which shold not be referenced by well-formed programs. */
534  static constexpr refl::const_string<0> name{ "" };
535 
536  /** This is a placeholder definition which shold not be referenced by well-formed programs. */
537  static constexpr std::tuple<> attributes{ };
538  };
539 
540  /**
541  * Specializes type_info__ so that a type's const-qualification is effectively discarded.
542  */
543  template <typename T>
544  struct type_info__<const T> : public type_info__<T> {};
545 
546  /**
547  * Specializes type_info__ so that a type's volatile-qualification is effectively discarded.
548  */
549  template <typename T>
550  struct type_info__<volatile T> : public type_info__<T> {};
551 
552  /**
553  * Specializes type_info__ so that a type's const-volatile-qualification is effectively discarded.
554  */
555  template <typename T>
556  struct type_info__<const volatile T> : public type_info__<T> {};
557 
558  } // namespace metadata
559 
560 } // namespace refl_impl
561 
562 namespace refl
563 {
564  namespace detail
565  {
566  template <typename T>
567  using type_info = refl_impl::metadata::type_info__<T>;
568 
569  template <typename T, size_t N>
570  using member_info = typename type_info<T>::template member<N>;
571  } // namespace detail
572 
573  /**
574  * @brief Contains tag types denoting the different types of reflectable members.
575  *
576  * This namespace contains a number of empty types that correspond to
577  * the different member types that refl-cpp supports reflection over.
578  */
579  namespace member
580  {
581  /**
582  * An empty type which is equivalent to refl::member_descriptor_base::member_type
583  * when the reflected member is a field.
584  *
585  * @see refl::descriptor::field_descriptor
586  */
587  struct field {};
588 
589  /**
590  * An empty type which is equivalent to refl::member_descriptor_base::member_type
591  * when the reflected member is a function.
592  *
593  * @see refl::descriptor::function_descriptor
594  */
595  struct function {};
596  }
597 
598  namespace descriptor
599  {
600  template <typename>
601  class type_descriptor;
602 
603  template <typename, size_t>
604  class field_descriptor;
605 
606  template <typename, size_t>
607  class function_descriptor;
608  } // namespace descriptor
609 
610  /**
611  * @brief Provides type-level operations for refl-cpp related use-cases.
612  *
613  * The refl::trait namespace provides type-level operations useful
614  * for compile-time metaprogramming.
615  */
616  namespace trait
617  {/**
618  * Removes all reference and cv-qualifiers from T.
619  * Equivalent to std::remove_cvref which is not currently
620  * available on all C++17 compilers.
621  */
622  template <typename T>
624  {
625  typedef std::remove_cv_t<std::remove_reference_t<T>> type;
626  };
627 
628  /**
629  * Removes all reference and cv-qualifiers from T.
630  * Equivalent to std::remove_cvref_t which is not currently
631  * available on all C++17 compilers.
632  */
633  template <typename T>
634  using remove_qualifiers_t = typename remove_qualifiers<T>::type;
635 
636  namespace detail
637  {
638  /** SFIANE support for detecting whether there is a type_info__ specialization for T. */
639  template <typename T>
640  decltype(typename refl::detail::type_info<T>::invalid_marker{}, std::false_type{}) is_reflectable_test(int);
641 
642  /** SFIANE support for detecting whether there is a type_info__ specialization for T. */
643  template <typename T>
644  std::true_type is_reflectable_test(...);
645  } // namespace detail
646 
647  /**
648  * Checks whether there is reflection metadata for the type T.
649  * Inherits from std::bool_constant<>
650  *
651  * @see REFL_TYPE
652  * @see REFL_AUTO
653  * @see refl::is_reflectable
654  */
655  template <typename T>
656  struct is_reflectable : decltype(detail::is_reflectable_test<T>(0))
657  {
658  };
659 
660  /**
661  * Checks whether there is reflection metadata for the type T.
662  * Inherits from std::bool_constant<>
663  *
664  * @see refl::trait::is_reflectable
665  */
666  template <typename T>
667  [[maybe_unused]] static constexpr bool is_reflectable_v{ is_reflectable<T>::value };
668 
669  namespace detail
670  {
671  /** SFIANE support for detecting whether the type T supports member .begin() and .end() operations. */
672  template <typename U>
673  [[maybe_unused]] static auto is_container_test(int) -> decltype(std::declval<U>().begin(), std::declval<U>().end(), std::true_type{});
674 
675  /** SFIANE support for detecting whether the type T supports member .begin() and .end() operations. */
676  template <typename U>
677  [[maybe_unused]] static std::false_type is_container_test(...);
678  }
679 
680  /**
681  * Checks whether objects of the type T support member .begin() and .end() operations.
682  */
683  template <typename T>
684  struct is_container : decltype(detail::is_container_test<T>(0))
685  {
686  };
687 
688  /**
689  * Checks whether objects of the type T support member .begin() and .end() operations.
690  */
691  template <typename T>
692  [[maybe_unused]] static constexpr bool is_container_v{ is_container<T>::value };
693 
694  namespace detail
695  {
696  template <size_t N, typename... Ts>
697  struct get;
698 
699  template <size_t N>
700  struct get<N>
701  {
702  static_assert(N > 0, "Missing arguments list for get<N, Ts...>!");
703  };
704 
705  template <size_t N, typename T, typename... Ts>
706  struct get<N, T, Ts...> : public get<N - 1, Ts...>
707  {
708  };
709 
710  template <typename T, typename... Ts>
711  struct get<0, T, Ts...>
712  {
713  typedef T type;
714  };
715 
716  template <size_t N, typename...>
717  struct skip;
718 
719  template <size_t N, typename T, typename... Ts>
720  struct skip<N, T, Ts...> : skip<N - 1, Ts...>
721  {
722  };
723 
724  template <typename T, typename... Ts>
725  struct skip<0, T, Ts...>
726  {
727  typedef type_list<T, Ts...> type;
728  };
729 
730  template <>
731  struct skip<0>
732  {
733  typedef type_list<> type;
734  };
735  }
736 
737  /// \private
738  template <size_t, typename>
739  struct get;
740 
741  /**
742  * Provides a member typedef type which is the
743  * N-th type in the provided type_list.
744  *
745  * \code{.cpp}
746  * typename get<0, type_list<int, float>>::type -> int
747  * typename get<1, type_list<int, float>>::type -> float
748  * \endcode
749  */
750  template <size_t N, typename... Ts>
751  struct get<N, type_list<Ts...>> : detail::get<N, Ts...>
752  {
753  };
754 
755  /**
756  * The N-th type in the provided type_list.
757  * @see get
758  */
759  template <size_t N, typename TypeList>
760  using get_t = typename get<N, TypeList>::type;
761 
762  /// \private
763  template <size_t, typename>
764  struct skip;
765 
766  /**
767  * Skips the first N types in the provided type_list.
768  * Provides a member typedef equivalent to the resuling type_list.
769  *
770  * \code{.cpp}
771  * typename skip<1, type_list<int, float, double>>::type -> type_list<float, double>
772  * typename skip<0, type_list<int, float, double>>::type -> type_list<int, float, double>
773  * \endcode
774  */
775  template <size_t N, typename... Ts>
776  struct skip<N, type_list<Ts...>> : detail::skip<N, Ts...>
777  {
778  };
779 
780  /**
781  * Skips the first N types in the provided type_list.
782  * @see skip
783  */
784  template <size_t N, typename TypeList>
785  using skip_t = typename skip<N, TypeList>::type;
786 
787  /// \private
788  template <typename>
789  struct as_type_list;
790 
791  /**
792  * Provides a member typedef type which is a type_list with
793  * template type parameters equivalent to the type parameters of the provided
794  * type. The provided type must be a template instance.
795  *
796  * \code{.cpp}
797  * typename as_type_list<std::tuple<int, float>>::type -> type_list<int, float>
798  * \endcode
799  */
800  template <template <typename...> typename T, typename... Ts>
801  struct as_type_list<T<Ts...>>
802  {
803  typedef type_list<Ts...> type;
804  };
805 
806  /// \private
807  template <typename T>
808  struct as_type_list : as_type_list<remove_qualifiers_t<T>>
809  {
810  };
811 
812  /**
813  * A typedef for a type_list with
814  * template type parameters equivalent to the type parameters of the provided
815  * type. The provided type must be a template instance.
816  * @see as_type_list
817  */
818  template <typename T>
819  using as_type_list_t = typename as_type_list<T>::type;
820 
821  /// \private
822  template <typename>
823  struct as_tuple;
824 
825  /**
826  * Provides a member typedef which is a std::tuple specialization with
827  * template type parameters equivalent to the type parameters of the provided
828  * type. The provided type must be a template specialization.
829  *
830  * \code{.cpp}
831  * typename as_tuple<type_list<int, float>>::type -> std::tuple<int, float>
832  * \endcode
833  */
834  template <template <typename...> typename T, typename... Ts>
835  struct as_tuple<T<Ts...>>
836  {
837  typedef std::tuple<Ts...> type;
838  };
839 
840  /// \private
841  template <typename T>
842  struct as_tuple : as_tuple<remove_qualifiers_t<T>>
843  {
844  };
845 
846  /**
847  * A typedef for a std::tuple specialization with
848  * template type parameters equivalent to the type parameters of the provided
849  * type. The provided type must be a template specialization.
850  * @see as_tuple
851  */
852  template <typename T>
853  using as_tuple_t = typename as_tuple<T>::type;
854 
855  /**
856  * Accesses first type in the list.
857  */
858  template <typename TypeList>
859  using first = get<0, TypeList>;
860 
861  /**
862  * Accesses last type in the list.
863  * @see last
864  */
865  template <typename TypeList>
866  using first_t = typename first<TypeList>::type;
867 
868  /**
869  * Accesses last type in the list.
870  */
871  template <typename TypeList>
872  using last = get<TypeList::size - 1, TypeList>;
873 
874  /**
875  * Accesses last type in the list.
876  * @see last
877  */
878  template <typename TypeList>
879  using last_t = typename last<TypeList>::type;
880 
881  /**
882  * Returns all but the first element of the list.
883  */
884  template <typename TypeList>
885  using tail = skip<1, TypeList>;
886 
887  /**
888  * Returns all but the first element of the list.
889  * @see tail
890  */
891  template <typename TypeList>
892  using tail_t = typename tail<TypeList>::type;
893 
894  namespace detail
895  {
896  template <typename, size_t, typename>
897  struct take;
898 
899  template <typename... Us>
900  struct take<type_list<Us...>, 0, type_list<>>
901  {
902  using type = type_list<Us...>;
903  };
904 
905  template <typename... Us, typename T, typename... Ts>
906  struct take<type_list<Us...>, 0, type_list<T, Ts...>>
907  {
908  using type = type_list<Us...>;
909  };
910 
911  template <size_t N, typename... Us, typename T, typename... Ts>
912  struct take<type_list<Us...>, N, type_list<T, Ts...>>
913  {
914  using type = typename take<type_list<Us..., T>, N - 1, type_list<Ts...>>::type;
915  };
916  }
917 
918  /**
919  * Returns the first N elements of the list.
920  */
921  template <size_t N, typename TypeList>
922  using take = detail::take<type_list<>, N, TypeList>;
923 
924  /**
925  * Returns the first N elements of the list.
926  */
927  template <size_t N, typename TypeList>
928  using take_t = typename take<N, TypeList>::type;
929 
930  /**
931  * Returns all but the last element of the list.
932  */
933  template <typename TypeList>
934  using init = take<TypeList::size - 1, TypeList>;
935 
936  /**
937  * Returns all but the last element of the list.
938  * @see tail
939  */
940  template <typename TypeList>
941  using init_t = typename init<TypeList>::type;
942 
943  namespace detail
944  {
945  template <typename, typename>
946  struct reverse_impl;
947 
948  template <typename... Us>
949  struct reverse_impl<type_list<Us...>, type_list<>>
950  {
951  using type = type_list<Us...>;
952  };
953 
954  template <typename... Us, typename T, typename... Ts>
955  struct reverse_impl<type_list<Us...>, type_list<T, Ts...>>
956  {
957  using type = typename reverse_impl<type_list<T, Us...>, type_list<Ts...>>::type;
958  };
959  } // namespace detail
960 
961  /**
962  * Reverses a list of types.
963  *
964  * \code{.cpp}
965  * typename reverse<type_list<int, float>>::type -> type_list<float, int>
966  * \endcode
967  */
968  template <typename TypeList>
969  struct reverse : detail::reverse_impl<type_list<>, TypeList>
970  {
971  };
972 
973  /**
974  * Reverses a list of types.
975  * @see reverse
976  */
977  template <typename TypeList>
978  using reverse_t = typename reverse<TypeList>::type;
979 
980  /**
981  * Concatenates N lists together.
982  *
983  * \code{.cpp}
984  * typename concat<type_list<int, float>, type_list<double>, type_list<long>>::type -> type_list<int, float, double, long>
985  * \endcode
986  */
987  template <typename...>
988  struct concat;
989 
990  /// \private
991  template <>
992  struct concat<>
993  {
994  using type = type_list<>;
995  };
996 
997  /// \private
998  template <typename... Ts>
999  struct concat<type_list<Ts...>>
1000  {
1001  using type = type_list<Ts...>;
1002  };
1003 
1004  /**
1005  * Concatenates two lists together.
1006  */
1007  /// \private
1008  template <typename... Ts, typename... Us>
1009  struct concat<type_list<Ts...>, type_list<Us...>>
1010  {
1011  using type = type_list<Ts..., Us...>;
1012  };
1013 
1014  /**
1015  * Concatenates N lists together.
1016  */
1017  /// \private
1018  template <typename TypeList1, typename TypeList2, typename... TypeLists>
1019  struct concat<TypeList1, TypeList2, TypeLists...> : concat<typename concat<TypeList1, TypeList2>::type, TypeLists...>
1020  {
1021  };
1022 
1023  /**
1024  * Concatenates two lists together.
1025  * @see concat
1026  */
1027  template <typename... Ts>
1028  using concat_t = typename concat<Ts...>::type;
1029 
1030  /**
1031  * Appends a type to the list.
1032  */
1033  template <typename T, typename TypeList>
1034  struct append : concat<TypeList, type_list<T>>
1035  {
1036  };
1037 
1038  /**
1039  * Appends a type to the list.
1040  * @see prepend
1041  */
1042  template <typename T, typename TypeList>
1043  using append_t = typename append<T, TypeList>::type;
1044 
1045  template <typename, typename>
1046  struct prepend;
1047 
1048  /**
1049  * Prepends a type to the list.
1050  */
1051  template <typename T, typename TypeList>
1052  struct prepend : concat<type_list<T>, TypeList>
1053  {
1054  };
1055 
1056  /**
1057  * Prepends a type to the list.
1058  * @see prepend
1059  */
1060  template <typename T, typename TypeList>
1061  using prepend_t = typename prepend<T, TypeList>::type;
1062 
1063  namespace detail
1064  {
1065  template <template<typename> typename, typename...>
1066  struct filter_impl;
1067 
1068  template <template<typename> typename Predicate>
1069  struct filter_impl<Predicate>
1070  {
1071  using type = type_list<>;
1072  };
1073 
1074  template <template<typename> typename Predicate, typename Head, typename... Tail>
1075  struct filter_impl<Predicate, Head, Tail...>
1076  {
1077  using type = std::conditional_t<Predicate<Head>::value,
1078  prepend_t<Head, typename filter_impl<Predicate, Tail...>::type>,
1079  typename filter_impl<Predicate, Tail...>::type
1080  >;
1081  };
1082 
1083  template <template<typename> typename, typename...>
1084  struct map_impl;
1085 
1086  template <template<typename> typename Mapper>
1087  struct map_impl<Mapper>
1088  {
1089  using type = type_list<>;
1090  };
1091 
1092  template <template<typename> typename Mapper, typename Head, typename ...Tail>
1093  struct map_impl<Mapper, Head, Tail...>
1094  {
1095  using type = typename prepend<typename Mapper<Head>::type,
1096  typename map_impl<Mapper, Tail...>::type>::type;
1097  };
1098  }
1099 
1100  /// \private
1101  template <template<typename> typename, typename>
1102  struct filter;
1103 
1104  /**
1105  * Filters a type_list according to a predicate template.
1106  *
1107  * \code{.cpp}
1108  * typename filter<std::is_reference, type_list<int, float&, double>>::type -> type_list<float&>
1109  * \endcode
1110  */
1111  template <template<typename> typename Predicate, typename... Ts>
1112  struct filter<Predicate, type_list<Ts...>>
1113  {
1114  using type = typename detail::filter_impl<Predicate, Ts...>::type;
1115  };
1116 
1117  /**
1118  * Filters a type_list according to a predicate template
1119  * with a static boolean member named "value" (e.g. std::is_trivial)
1120  * @see filter
1121  */
1122  template <template<typename> typename Predicate, typename TypeList>
1123  using filter_t = typename filter<Predicate, TypeList>::type;
1124 
1125  /// \private
1126  template <template<typename> typename, typename>
1127  struct map;
1128 
1129  /**
1130  * Transforms a type_list according to a predicate template.
1131  *
1132  * \code{.cpp}
1133  * typename map<std::add_reference, type_list<int, float&, double>>::type -> type_list<int&, float&, double&>
1134  * \endcode
1135  */
1136  template <template<typename> typename Mapper, typename... Ts>
1137  struct map<Mapper, type_list<Ts...>>
1138  {
1139  using type = typename detail::map_impl<Mapper, Ts...>::type;
1140  };
1141 
1142  /**
1143  * Transforms a type_list according to a predicate template
1144  * with a typedef named "type" (e.g. std::remove_reference)
1145  * @see map
1146  */
1147  template <template<typename> typename Mapper, typename... Ts>
1148  using map_t = typename map<Mapper, Ts...>::type;
1149 
1150  namespace detail
1151  {
1152  template <typename T>
1153  struct is_instance : public std::false_type {};
1154 
1155  template <template<typename...> typename T, typename... Args>
1156  struct is_instance<T<Args...>> : public std::true_type {};
1157  } // namespace detail
1158 
1159  /**
1160  * Detects whether T is a template specialization.
1161  * Inherits from std::bool_constant<>.
1162  *
1163  * \code{.cpp}
1164  * is_instance<type_list<>>::value -> true
1165  * is_instance<int>::value -> false
1166  * \endcode
1167  */
1168  template <typename T>
1169  struct is_instance : detail::is_instance<T>
1170  {
1171  };
1172 
1173  /**
1174  * Detects whether T is a template specialization.
1175  * @see is_instance
1176  */
1177  template <typename T>
1178  [[maybe_unused]] static constexpr bool is_instance_v{ is_instance<T>::value };
1179 
1180  namespace detail
1181  {
1182  /**
1183  * Checks if T == U<Args...>.
1184  * If U<Args...> != T or is invalid the result is false.
1185  */
1186  template <typename T, template<typename...> typename U, typename... Args>
1187  struct is_same_template
1188  {
1189  template <template<typename...> typename V, typename = V<Args...>>
1190  static auto test(int) -> std::is_same<V<Args...>, T>;
1191 
1192  template <template<typename...> typename V>
1193  static std::false_type test(...);
1194 
1195  static constexpr bool value{decltype(test<U>(0))::value};
1196  };
1197 
1198  template <template<typename...> typename T, typename U>
1199  struct is_instance_of : public std::false_type {};
1200 
1201  template <template<typename...> typename T, template<typename...> typename U, typename... Args>
1202  struct is_instance_of<T, U<Args...>> : public is_same_template<U<Args...>, T, Args...>
1203  {
1204  };
1205  }
1206 
1207  /**
1208  * Detects whther the type U is a template specialization of T.
1209  * (e.g. is_instance_of<std::vector<>, std::vector<int>>)
1210  * Inherits from std::bool_constant<>.
1211  *
1212  * \code{.cpp}
1213  * is_instance_of<type_list, type_list<int>>::value -> true
1214  * is_instance_of<type_list, std::tuple<int>>::value -> false
1215  * \endcode
1216  */
1217  template <template<typename...>typename T, typename U>
1218  struct is_instance_of : detail::is_instance_of<T, std::remove_cv_t<U>>
1219  {
1220  };
1221 
1222  /**
1223  * Detects whther the type U is a template specialization of T.
1224  * @see is_instance_of_v
1225  */
1226  template <template<typename...>typename T, typename U>
1227  [[maybe_unused]] static constexpr bool is_instance_of_v{ is_instance_of<T, U>::value };
1228 
1229  /// \private
1230  template <typename, typename>
1231  struct contains;
1232 
1233  /**
1234  * Checks whether T is contained in the list of types.
1235  * Inherits from std::bool_constant<>.
1236  *
1237  * \code{.cpp}
1238  * contains<int, type_list<int, float>>::value -> true
1239  * contains<double, type_list<int, float>>::value -> false
1240  * \endcode
1241  */
1242  template <typename T, typename... Ts>
1243  struct contains<T, type_list<Ts...>> : std::disjunction<std::is_same<std::remove_cv_t<T>, std::remove_cv_t<Ts>>...>
1244  {
1245  };
1246 
1247  /**
1248  * Checks whether T is contained in the list of types.
1249  * @see contains
1250  */
1251  template <typename T, typename TypeList>
1252  [[maybe_unused]] static constexpr bool contains_v = contains<T, TypeList>::value;
1253 
1254  /// \private
1255  template <template<typename...> typename, typename>
1256  struct contains_instance;
1257 
1258  /**
1259  * Checks whether an instance of the template T is contained in the list of types.
1260  * Inherits from std::bool_constant<>.
1261  *
1262  * \code{.cpp}
1263  * contains_instance<std::tuple, type_list<int, float, std::tuple<short, double>>>::value -> true
1264  * contains_instance<std::vector, type_list<int, float, std::tuple<short, double>>>::value -> false
1265  * \endcode
1266  */
1267  template <template<typename...> typename T, typename... Ts>
1268  struct contains_instance<T, type_list<Ts...>> : std::disjunction<trait::is_instance_of<T, std::remove_cv_t<Ts>>...>
1269  {
1270  };
1271 
1272  /**
1273  * Checks whether an instance of the template T is contained in the list of types.
1274  * @see contains_instance
1275  */
1276  template <template<typename...> typename T, typename TypeList>
1277  [[maybe_unused]] static constexpr bool contains_instance_v = contains_instance<T, TypeList>::value;
1278 
1279  /// \private
1280  template <typename, typename>
1281  struct contains_base;
1282 
1283  /**
1284  * Checks whether a type deriving from T is contained in the list of types.
1285  * Inherits from std::bool_constant<>.
1286  *
1287  * \code{.cpp}
1288  * struct Base {};
1289  * struct Derived : Base {};
1290  * contains_base<Base, type_list<int, float, Derived>>::value -> true
1291  * contains_base<Base, type_list<int, float, Base>>::value -> true
1292  * contains_base<int, type_list<int, float, Derived>>::value -> false
1293  * \endcode
1294  */
1295  template <typename T, typename... Ts>
1296  struct contains_base<T, type_list<Ts...>> : std::disjunction<std::is_base_of<std::remove_cv_t<T>, std::remove_cv_t<Ts>>...>
1297  {
1298  };
1299 
1300  /**
1301  * Checks whether a type deriving from T is contained in the list of types.
1302  * @see contains_base
1303  */
1304  template <typename T, typename TypeList>
1305  [[maybe_unused]] static constexpr bool contains_base_v = contains_base<T, TypeList>::value;
1306 
1307  namespace detail
1308  {
1309  template <typename T, ptrdiff_t N, typename... Ts>
1310  constexpr ptrdiff_t index_of() noexcept
1311  {
1312  if constexpr (sizeof...(Ts) <= N) return -1;
1313  else if constexpr (std::is_same_v<T, trait::get_t<N, type_list<Ts...>>>) return N;
1314  else return index_of<T, N + 1, Ts...>();
1315  }
1316 
1317  template <typename T, ptrdiff_t N, typename... Ts>
1318  constexpr ptrdiff_t index_of_base() noexcept
1319  {
1320  if constexpr (sizeof...(Ts) <= N) return -1;
1321  else if constexpr (std::is_base_of_v<T, trait::get_t<N, type_list<Ts...>>>) return N;
1322  else return index_of_base<T, N + 1, Ts...>();
1323  }
1324 
1325  template <template<typename...> typename T, ptrdiff_t N, typename... Ts>
1326  constexpr ptrdiff_t index_of_instance() noexcept
1327  {
1328  if constexpr (sizeof...(Ts) <= N) return -1;
1329  else if constexpr (is_instance_of_v<T, trait::get_t<N, type_list<Ts...>>>) return N;
1330  else return index_of_instance<T, N + 1, Ts...>();
1331  }
1332 
1333  // This variable template was introduced to fix the build on VS2017, which
1334  // chokes when invoking index_of_instance() directly from struct index_of_instance.
1335  template <template<typename...> typename T, ptrdiff_t N, typename... Ts>
1336  static constexpr ptrdiff_t index_of_instance_v = index_of_instance<T, N, Ts...>();
1337  } // namespace detail
1338 
1339  /// \private
1340  template <typename, typename>
1341  struct index_of;
1342 
1343  /**
1344  * The index of the type in the type list, -1 if it doesn't exist.
1345  * @see contains
1346  */
1347  template <typename T, typename... Ts>
1348  struct index_of<T, type_list<Ts...>> : std::integral_constant<ptrdiff_t, detail::index_of<T, 0, Ts...>()>
1349  {
1350  };
1351 
1352  /**
1353  * The index of the type in the type list, -1 if it doesn't exist.
1354  * @see index_of
1355  */
1356  template <typename T, typename TypeList>
1357  static constexpr ptrdiff_t index_of_v = index_of<T, TypeList>::value;
1358 
1359  /// \private
1360  template <typename, typename>
1361  struct index_of_base;
1362 
1363  /**
1364  * The index of the type in the type list that is derived from T, -1 if it doesn't exist.
1365  * @see contains_base
1366  */
1367  template <typename T, typename... Ts>
1368  struct index_of_base<T, type_list<Ts...>> : std::integral_constant<ptrdiff_t, detail::index_of_base<T, 0, Ts...>()>
1369  {
1370  };
1371 
1372  /**
1373  * The index of the type in the type list that is derived from T, -1 if it doesn't exist.
1374  * @see index_of_base
1375  */
1376  template <typename T, typename TypeList>
1377  static constexpr ptrdiff_t index_of_base_v = index_of_base<T, TypeList>::value;
1378 
1379  /// \private
1380  template <template<typename...> typename, typename>
1381  struct index_of_instance;
1382 
1383  /**
1384  * The index of the type in the type list that is a template instance of T, -1 if it doesn't exist.
1385  * @see contains_instance
1386  */
1387  template <template<typename...> typename T, typename... Ts>
1388  struct index_of_instance<T, type_list<Ts...>> : std::integral_constant<ptrdiff_t, detail::index_of_instance_v<T, 0, Ts...>>
1389  {
1390  };
1391 
1392  /**
1393  * The index of the type in the type list that is a template instance of T, -1 if it doesn't exist.
1394  * @see index_of_instance
1395  */
1396  template <template<typename...> typename T, typename TypeList>
1397  static constexpr ptrdiff_t index_of_instance_v = index_of_instance<T, TypeList>::value;
1398 
1399  namespace detail
1400  {
1401  template <typename, typename>
1402  struct unique_impl;
1403 
1404  template <typename UniqueList>
1405  struct unique_impl<UniqueList, type_list<>>
1406  {
1407  using type = UniqueList;
1408  };
1409 
1410  template <typename UniqueList, typename T, typename... Ts>
1411  struct unique_impl<UniqueList, type_list<T, Ts...>> :
1412  std::conditional_t<contains_v<T, UniqueList>,
1413  unique_impl<UniqueList, type_list<Ts...>>,
1414  unique_impl<append_t<T, UniqueList>, type_list<Ts...>>>
1415  {
1416  };
1417  } // namespace detail
1418 
1419  /**
1420  * Creates a new list containing the repeating elements in the source list only once.
1421  *
1422  * \code{.cpp}
1423  * typename unique<type_list<int, float, int>>::type -> type_list<int, float>
1424  * \endcode
1425  */
1426  template <typename T>
1427  struct unique : detail::unique_impl<type_list<>, T>
1428  {
1429  };
1430 
1431  /**
1432  * Creates a new list containing the repeating elements in the source list only once.
1433  */
1434  template <typename T>
1435  using unique_t = typename unique<T>::type;
1436 
1437  } // namespace trait
1438 
1439  namespace util
1440  {
1441  /**
1442  * Ignores all parameters. Can take an optional template parameter
1443  * specifying the return type of ignore. The return object is iniailized by {}.
1444  */
1445  template <typename T = int, typename... Ts>
1446  constexpr int ignore(Ts&&...) noexcept
1447  {
1448  return {};
1449  }
1450 
1451  /**
1452  * Returns the input paratemeter as-is. Useful for expanding variadic
1453  * template lists when only one arguments is known to be present.
1454  */
1455  template <typename T>
1456  constexpr decltype(auto) identity(T&& t) noexcept
1457  {
1458  return std::forward<T>(t);
1459  }
1460 
1461  /**
1462  * Adds const to the input reference.
1463  */
1464  template <typename T>
1465  constexpr const T& make_const(const T& value) noexcept
1466  {
1467  return value;
1468  }
1469 
1470  /**
1471  * Adds const to the input reference.
1472  */
1473  template <typename T>
1474  constexpr const T& make_const(T& value) noexcept
1475  {
1476  return value;
1477  }
1478 
1479  /**
1480  * Creates an array of type 'T' from the provided tuple.
1481  * The common type T needs to be specified, in order to prevent any
1482  * errors when using the overload taking an empty std::tuple (as there is no common type then).
1483  */
1484  template <typename T, typename... Ts>
1485  constexpr std::array<T, sizeof...(Ts)> to_array(const std::tuple<Ts...>& tuple) noexcept
1486  {
1487  return std::apply([](auto&& ... args) -> std::array<T, sizeof...(Ts)> { return { std::forward<decltype(args)>(args)... }; }, tuple);
1488  }
1489 
1490  /**
1491  * Creates an empty array of type 'T.
1492  */
1493  /// \private
1494  template <typename T>
1495  constexpr std::array<T, 0> to_array(const std::tuple<>&) noexcept
1496  {
1497  return {};
1498  }
1499 
1500  namespace detail
1501  {
1502  template <typename T, size_t... Idx>
1503  constexpr auto to_tuple([[maybe_unused]] const std::array<T, sizeof...(Idx)>& array, std::index_sequence<Idx...>) noexcept
1504  {
1505  if constexpr (sizeof...(Idx) == 0) return std::tuple<>{};
1506  else return std::make_tuple(std::get<Idx>(array)...);
1507  }
1508  }
1509 
1510  /**
1511  * Creates a tuple from the provided array.
1512  */
1513  template <typename T, size_t N>
1514  constexpr auto to_tuple(const std::array<T, N>& array) noexcept
1515  {
1516  return detail::to_tuple<T>(array, std::make_index_sequence<N>{});
1517  }
1518 
1519  /**
1520  * Creates a matching std::tuple from a type_list.
1521  * Types in the type_list must be Trivial.
1522  */
1523  template <typename... Ts>
1524  constexpr std::tuple<Ts...> as_tuple(type_list<Ts...>) noexcept
1525  {
1526  static_assert((... && std::is_trivial_v<Ts>), "Non-trivial types in type_list as not allowed!");
1527  return {};
1528  }
1529 
1530  /**
1531  * Creates a matching type_list from a std::tuple.
1532  */
1533  template <typename... Ts>
1534  constexpr type_list<Ts...> as_type_list(const std::tuple<Ts...>&) noexcept
1535  {
1536  return {};
1537  }
1538 
1539  namespace detail
1540  {
1541  template <typename F, typename T>
1542  constexpr auto invoke_optional_index(F&& f, T&& t, size_t idx, int) -> decltype(f(std::forward<T>(t), idx))
1543  {
1544  return f(std::forward<T>(t), idx);
1545  }
1546 
1547  template <typename F, typename T>
1548  constexpr auto invoke_optional_index(F&& f, T&& t, size_t, ...) -> decltype(f(std::forward<T>(t)))
1549  {
1550  return f(std::forward<T>(t));
1551  }
1552 
1553  template <typename F, typename... Carry>
1554  constexpr auto eval_in_order_to_tuple(type_list<>, std::index_sequence<>, F&&, Carry&&... carry)
1555  {
1556  if constexpr (sizeof...(Carry) == 0) return std::tuple<>{};
1557  else return std::make_tuple(std::forward<Carry>(carry)...);
1558  }
1559  // This workaround is needed since C++ does not specify
1560  // the order in which function arguments are evaluated and this leads
1561  // to incorrect order of evaluation (noticeable when using indexes).
1562  // Otherwise we could simply do std::make_tuple(f(Ts{}, Idx)...).
1563  template <typename F, typename T, typename... Ts, size_t I, size_t... Idx, typename... Carry>
1564  constexpr auto eval_in_order_to_tuple(type_list<T, Ts...>, std::index_sequence<I, Idx...>, F&& f, Carry&&... carry)
1565  {
1566  static_assert(std::is_trivial_v<T>, "Argument is a non-trivial type!");
1567 
1568  auto&& result = invoke_optional_index(f, T{}, I, 0);
1569  return eval_in_order_to_tuple(
1570  type_list<Ts...>{},
1571  std::index_sequence<Idx...>{},
1572  std::forward<F>(f),
1573  std::forward<Carry>(carry)..., // carry the previous results over
1574  std::forward<decltype(result)>(result) // pass the current result after them
1575  );
1576  }
1577  }
1578 
1579  /**
1580  * Applies function F to each type in the type_list, aggregating
1581  * the results in a tuple. F can optionally take an index of type size_t.
1582  *
1583  * \code{.cpp}
1584  * map_to_tuple(reflect_types(type_list<int, float, double>{}), [](auto td) {
1585  * return get_name(td);
1586  * })
1587  * -> std::tuple{const_string{"int"}, const_string{"float"}, const_string{"double"}}
1588  * \endcode
1589  */
1590  template <typename F, typename... Ts>
1591  constexpr auto map_to_tuple(type_list<Ts...> list, F&& f)
1592  {
1593  return detail::eval_in_order_to_tuple(list, std::make_index_sequence<sizeof...(Ts)>{}, std::forward<F>(f));
1594  }
1595 
1596  /**
1597  * Applies function F to each type in the type_list, aggregating
1598  * the results in an array. F can optionally take an index of type size_t.
1599  *
1600  * \code{.cpp}
1601  * map_to_array<std::string>(reflect_types(type_list<int, float, double>{}), [](auto td) {
1602  * return get_name(td).str();
1603  * })
1604  * -> std::array{std::string{"int"}, std::string{"float"}, std::string{"double"}}
1605  * \endcode
1606  */
1607  template <typename T, typename F, typename... Ts>
1608  constexpr auto map_to_array(type_list<Ts...> list, F&& f)
1609  {
1610  return to_array<T>(map_to_tuple(list, std::forward<F>(f)));
1611  }
1612 
1613  /**
1614  * Applies function F to each type in the type_list.
1615  * F can optionally take an index of type size_t.
1616  *
1617  * \code{.cpp}
1618  * for_each(reflect_types(type_list<int, float, double>{}), [](auto td) {
1619  * std::cout << get_name(td) << '\n';
1620  * });
1621  * \endcode
1622  */
1623  template <typename F, typename... Ts>
1624  constexpr void for_each(type_list<Ts...> list, F&& f)
1625  {
1626  map_to_tuple(list, [&](auto&& val, size_t idx)
1627  {
1628  detail::invoke_optional_index(f, std::forward<decltype(val)>(val), idx, 0);
1629  return 0;
1630  });
1631  }
1632 
1633  /*
1634  * Returns the initial_value unchanged.
1635  */
1636  /// \private
1637  template <typename R, typename F, typename... Ts>
1638  constexpr R accumulate(type_list<>, F&&, R&& initial_value)
1639  {
1640  return std::forward<R>(initial_value);
1641  }
1642 
1643  /*
1644  * Applies an accumulation function F to each type in the type_list.
1645  * Note: Breaking changes introduced in v0.7.0:
1646  * Behaviour changed to imitate std::accumulate.
1647  * F can now no longer take a second index argument.
1648  */
1649  template <typename R, typename F, typename T, typename... Ts>
1650  constexpr auto accumulate(type_list<T, Ts...>, F&& f, R&& initial_value)
1651  {
1652  static_assert(std::is_trivial_v<T>, "Argument is a non-trivial type!");
1653 
1654  return accumulate(type_list<Ts...> {},
1655  std::forward<F>(f),
1656  std::forward<std::invoke_result_t<F&&, R&&, T&&>>(
1657  f(std::forward<R>(initial_value), T {})));
1658  }
1659 
1660  /**
1661  * Counts the number of times the predicate F returns true.
1662  * Note: Breaking changes introduced in v0.7.0:
1663  * F can now no longer take a second index argument.
1664  */
1665  template <typename F, typename... Ts>
1666  constexpr size_t count_if(type_list<Ts...> list, F&& f)
1667  {
1668  return accumulate<size_t>(list,
1669  [&](size_t acc, const auto& t) -> size_t { return acc + (f(t) ? 1 : 0); },
1670  0);
1671  }
1672 
1673  namespace detail
1674  {
1675  template <typename F, typename... Carry>
1676  constexpr auto filter(const F&, type_list<>, type_list<Carry...> carry)
1677  {
1678  return carry;
1679  }
1680 
1681  template <typename F, typename T, typename... Ts, typename... Carry>
1682  constexpr auto filter(F f, type_list<T, Ts...>, type_list<Carry...>)
1683  {
1684  static_assert(std::is_trivial_v<T>, "Argument is a non-trivial type!");
1685  if constexpr (f(T{})) {
1686  return filter(f, type_list<Ts...>{}, type_list<Carry..., T>{});
1687  }
1688  else {
1689  return filter(f, type_list<Ts...>{}, type_list<Carry...>{});
1690  }
1691  }
1692  }
1693 
1694  /**
1695  * Filters the list according to a *constexpr* predicate.
1696  * Calling f(Ts{})... should be valid in a constexpr context.
1697  *
1698  * \code{.cpp}
1699  * filter(reflect_types(type_list<int, long, float>{}), [](auto td) {
1700  * return std::is_integral_v<typename decltype(td)::type>;
1701  * })
1702  * -> type_list<type_descriptor<int>, type_descriptor<long>>
1703  * \endcode
1704  */
1705  template <typename F, typename... Ts>
1706  constexpr auto filter(type_list<Ts...> list, F&& f)
1707  {
1708  return decltype(detail::filter(std::forward<F>(f), list, type_list<>{}))();
1709  }
1710 
1711  /**
1712  * Returns the first instance that matches the *constexpr* predicate.
1713  * Calling f(Ts{})... should be valid in a constexpr context.
1714  */
1715  template <typename F, typename... Ts>
1716  constexpr auto find_first(type_list<Ts...> list, F&& f)
1717  {
1718  using result_list = decltype(detail::filter(std::forward<F>(f), list, type_list<>{}));
1719  static_assert(result_list::size != 0, "find_first did not match anything!");
1720  return trait::get_t<0, result_list>{};
1721  }
1722 
1723  /**
1724  * Returns the only instance that matches the *constexpr* predicate.
1725  * If there is no match or multiple matches, fails with static_assert.
1726  * Calling f(Ts{})... should be valid in a constexpr context.
1727  */
1728  template <typename F, typename... Ts>
1729  constexpr auto find_one(type_list<Ts...> list, F&& f)
1730  {
1731  using result_list = decltype(detail::filter(std::forward<F>(f), list, type_list<>{}));
1732  static_assert(result_list::size != 0, "find_one did not match anything!");
1733  static_assert(result_list::size == 1, "Cannot resolve multiple matches in find_one!");
1734  return trait::get_t<0, result_list>{};
1735  }
1736 
1737  /**
1738  * Returns true if any item in the list matches the predicate.
1739  * Calling f(Ts{})... should be valid in a constexpr context.
1740  */
1741  template <typename F, typename T, typename... Ts>
1742  constexpr bool contains(type_list<T, Ts...> list, F&& f)
1743  {
1744  using result_list = decltype(detail::filter(std::forward<F>(f), list, type_list<>{}));
1745  return result_list::size > 0;
1746  }
1747 
1748  /**
1749  * Returns true if the type_list contains the specified type.
1750  * @see refl::trait::contains
1751  */
1752  template <typename T, typename... Ts>
1753  constexpr bool contains(type_list<Ts...>)
1754  {
1755  return trait::contains_v<T, type_list<Ts...>>;
1756  }
1757 
1758  /**
1759  * Returns true if the tuple contains the specified type or a supertype.
1760  * @see refl::trait::contains_base
1761  */
1762  template <typename T, typename... Ts>
1763  constexpr bool contains_base(const std::tuple<Ts...>&)
1764  {
1765  return trait::contains_base_v<T, type_list<Ts...>>;
1766  }
1767 
1768  /**
1769  * Returns true if the tuple contains an instance of the specified type.
1770  * @see refl::trait::contains_instance
1771  */
1772  template <template <typename...> typename T, typename... Ts>
1773  constexpr bool contains_instance(const std::tuple<Ts...>&)
1774  {
1775  return trait::contains_instance_v<T, type_list<Ts...>>;
1776  }
1777 
1778  /**
1779  * Applies a function to the elements of the type_list.
1780  *
1781  * \code{.cpp}
1782  * apply(reflect_types(type_list<int, long, float>{}), [](auto td_int, auto td_long, auto td_float) {
1783  * return get_name(td_int) + " " +get_name(td_long) + " " + get_name(td_float);
1784  * })
1785  * -> "int long float"
1786  * \endcode
1787  */
1788  template <typename... Ts, typename F>
1789  constexpr auto apply(type_list<Ts...>, F&& f)
1790  {
1791  return f(Ts{}...);
1792  }
1793 
1794  /** A synonym for std::get<N>(tuple). */
1795  template <size_t N, typename... Ts>
1796  constexpr auto& get(std::tuple<Ts...>& ts) noexcept
1797  {
1798  return std::get<N>(ts);
1799  }
1800 
1801  /** A synonym for std::get<N>(tuple). */
1802  template <size_t N, typename... Ts>
1803  constexpr const auto& get(const std::tuple<Ts...>& ts) noexcept
1804  {
1805  return std::get<N>(ts);
1806  }
1807 
1808  /** A synonym for std::get<T>(tuple). */
1809  template <typename T, typename... Ts>
1810  constexpr T& get(std::tuple<Ts...>& ts) noexcept
1811  {
1812  return std::get<T>(ts);
1813  }
1814 
1815  /** A synonym for std::get<T>(tuple). */
1816  template <typename T, typename... Ts>
1817  constexpr const T& get(const std::tuple<Ts...>& ts) noexcept
1818  {
1819  return std::get<T>(ts);
1820  }
1821 
1822  /** Returns the value of type U, where U is a template instance of T. */
1823  template <template<typename...> typename T, typename... Ts>
1824  constexpr auto& get_instance(std::tuple<Ts...>& ts) noexcept
1825  {
1826  static_assert((... || trait::is_instance_of_v<T, Ts>), "The tuple does not contain a type that is a template instance of T!");
1827  constexpr size_t idx = static_cast<size_t>(trait::index_of_instance_v<T, type_list<Ts...>>);
1828  return std::get<idx>(ts);
1829  }
1830 
1831  /** Returns the value of type U, where U is a template instance of T. */
1832  template <template<typename...> typename T, typename... Ts>
1833  constexpr const auto& get_instance(const std::tuple<Ts...>& ts) noexcept
1834  {
1835  static_assert((... || trait::is_instance_of_v<T, Ts>), "The tuple does not contain a type that is a template instance of T!");
1836  constexpr size_t idx = static_cast<size_t>(trait::index_of_instance_v<T, type_list<Ts...>>);
1837  return std::get<idx>(ts);
1838  }
1839 
1840  /**
1841  * Converts a type_list of types to a type_list of the type_descriptors for these types.
1842  *
1843  * \code{.cpp}
1844  * reflect_types(type_list<int, float>{}) -> type_list<type_descriptor<int>, type_descriptor<float>>{}
1845  * \endcode
1846  */
1847  template <typename... Ts>
1848  constexpr type_list<descriptor::type_descriptor<Ts>...> reflect_types(type_list<Ts...>) noexcept
1849  {
1850  return {};
1851  }
1852 
1853  /**
1854  * Converts a type_list of type_descriptors to a type_list of the target types.
1855  *
1856  * \code{.cpp}
1857  * unreflect_types(type_list<type_descriptor<int>, type_descriptor<float>>{}) -> type_list<int, float>{}
1858  * \endcode
1859  */
1860  template <typename... Ts>
1861  constexpr type_list<Ts...> unreflect_types(type_list<descriptor::type_descriptor<Ts>...>) noexcept
1862  {
1863  return {};
1864  }
1865  } // namespace util
1866 
1867  /**
1868  * @brief Contains the definitions of the built-in attributes
1869  *
1870  * Contains the definitions of the built-in attributes which
1871  * are implicitly available in macro context as well as the
1872  * attr::usage namespace which contains constraints
1873  * for user-provieded attributes.
1874  *
1875  * # Examples
1876  * ```
1877  * REFL_TYPE(Point, debug(custom_printer))
1878  * REFL_FIELD(x)
1879  * REFL_FIELD(y)
1880  * REFL_END
1881  * ```
1882  */
1883  namespace attr
1884  {
1885  /**
1886  * @brief Contains a number of constraints applicable to refl-cpp attributes.
1887  *
1888  * Contains base types which create compile-time constraints
1889  * that are verified by refl-cpp. These base-types must be inherited
1890  * by custom attribute types.
1891  */
1892  namespace usage
1893  {
1894  /**
1895  * Specifies that an attribute type inheriting from this type can
1896  * only be used with REFL_TYPE()
1897  */
1898  struct type {};
1899 
1900  /**
1901  * Specifies that an attribute type inheriting from this type can
1902  * only be used with REFL_FUNC()
1903  */
1904  struct function {};
1905 
1906  /**
1907  * Specifies that an attribute type inheriting from this type can
1908  * only be used with REFL_FIELD()
1909  */
1910  struct field {};
1911 
1912  /**
1913  * Specifies that an attribute type inheriting from this type can
1914  * only be used with REFL_FUNC or REFL_FIELD.
1915  */
1916  struct member : public function, public field{};
1917 
1918  /**
1919  * Specifies that an attribute type inheriting from this type can
1920  * only be used with any one of REFL_TYPE, REFL_FIELD, REFL_FUNC.
1921  */
1922  struct any : public member, public type {};
1923  }
1924 
1925  /**
1926  * Used to decorate a function that serves as a property.
1927  * Takes an optional friendly name.
1928  */
1929  struct property : public usage::function
1930  {
1931  const std::optional<const char*> friendly_name;
1932 
1933  constexpr property() noexcept
1934  : friendly_name{}
1935  {
1936  }
1937 
1938  constexpr property(const char* friendly_name) noexcept
1939  : friendly_name(friendly_name)
1940  {
1941  }
1942  };
1943 
1944  /**
1945  * Used to specify how a type should be displayed in debugging contexts.
1946  */
1947  template <typename F>
1948  struct debug : public usage::any
1949  {
1950  const F write;
1951 
1952  constexpr debug(F write)
1953  : write(write)
1954  {
1955  }
1956  };
1957 
1958  /**
1959  * Used to specify the base types of the target type.
1960  */
1961  template <typename... Ts>
1963  {
1964  /** An alias for a type_list of the base types. */
1965  typedef type_list<Ts...> list_type;
1966 
1967  /** An instance of a type_list of the base types. */
1968  static constexpr list_type list{ };
1969  };
1970 
1971  /**
1972  * Used to specify the base types of the target type.
1973  */
1974  template <typename... Ts>
1975  [[maybe_unused]] static constexpr base_types<Ts...> bases{ };
1976  } // namespace attr
1977 
1978 
1979  namespace detail
1980  {
1981  namespace macro_exports
1982  {
1983  using attr::property;
1984  using attr::debug;
1985  using attr::bases;
1986  }
1987  }
1988 
1989  namespace trait
1990  {
1991  namespace detail
1992  {
1993  template <typename T>
1994  auto member_type_test(int) -> decltype(typename T::member_type{}, std::true_type{});
1995 
1996  template <typename T>
1997  std::false_type member_type_test(...);
1998  }
1999 
2000  /**
2001  * A trait for detecting whether the type 'T' is a member descriptor.
2002  */
2003  template <typename T>
2004  struct is_member : decltype(detail::member_type_test<T>(0))
2005  {
2006  };
2007 
2008  /**
2009  * A trait for detecting whether the type 'T' is a member descriptor.
2010  */
2011  template <typename T>
2012  [[maybe_unused]] static constexpr bool is_member_v{ is_member<T>::value };
2013 
2014  namespace detail
2015  {
2016  template <typename T>
2017  struct is_field_2 : std::is_base_of<typename T::member_type, member::field>
2018  {
2019  };
2020  }
2021 
2022  /**
2023  * A trait for detecting whether the type 'T' is a field descriptor.
2024  */
2025  template <typename T>
2026  struct is_field : std::conjunction<is_member<T>, detail::is_field_2<T>>
2027  {
2028  };
2029 
2030  /**
2031  * A trait for detecting whether the type 'T' is a field descriptor.
2032  */
2033  template <typename T>
2034  [[maybe_unused]] static constexpr bool is_field_v{ is_field<T>::value };
2035 
2036  namespace detail
2037  {
2038  template <typename T>
2039  struct is_function_2 : std::is_base_of<typename T::member_type, member::function>
2040  {
2041  };
2042  }
2043 
2044  /**
2045  * A trait for detecting whether the type 'T' is a function descriptor.
2046  */
2047  template <typename T>
2048  struct is_function : std::conjunction<is_member<T>, detail::is_function_2<T>>
2049  {
2050  };
2051 
2052  /**
2053  * A trait for detecting whether the type 'T' is a function descriptor.
2054  */
2055  template <typename T>
2056  [[maybe_unused]] static constexpr bool is_function_v{ is_function<T>::value };
2057 
2058  /**
2059  * Detects whether the type T is a type_descriptor.
2060  * Inherits from std::bool_constant<>.
2061  */
2062  template <typename T>
2063  struct is_type : is_instance_of<descriptor::type_descriptor, T>
2064  {
2065  };
2066 
2067  /**
2068  * Detects whether the type T is a type_descriptor.
2069  * @see is_type
2070  */
2071  template <typename T>
2072  [[maybe_unused]] constexpr bool is_type_v{ is_type<T>::value };
2073 
2074  /**
2075  * A trait for detecting whether the type 'T' is a refl-cpp descriptor.
2076  */
2077  template <typename T>
2078  struct is_descriptor : std::disjunction<is_type<T>, is_member<T>>
2079  {
2080  };
2081 
2082  /**
2083  * A trait for detecting whether the type 'T' is a refl-cpp descriptor.
2084  */
2085  template <typename T>
2086  [[maybe_unused]] static constexpr bool is_descriptor_v{ is_descriptor<T>::value };
2087 
2088 
2089  /** Checks whether T is marked as a property. */
2090  template <typename T>
2091  struct is_property : std::bool_constant<
2092  trait::is_function_v<T> && trait::contains_v<attr::property, typename T::attribute_types>>
2093  {
2094  };
2095 
2096  /** Checks whether T is marked as a property. */
2097  template <typename T>
2098  [[maybe_unused]] static constexpr bool is_property_v{ is_property<T>::value };
2099  } // namespace trait
2100 
2101  /**
2102  * @brief Contains the basic reflection primitives
2103  * as well as functions operating on those primitives
2104  */
2105  namespace descriptor
2106  {
2107  namespace detail
2108  {
2109  template <typename Member>
2110  struct static_field_invoker
2111  {
2112  static constexpr auto invoke() -> decltype(*Member::pointer)
2113  {
2114  return *Member::pointer;
2115  }
2116 
2117  template <typename U, typename M = Member, std::enable_if_t<M::is_writable, int> = 0>
2118  static constexpr auto invoke(U&& value) -> decltype(*Member::pointer = std::forward<U>(value))
2119  {
2120  return *Member::pointer = std::forward<U>(value);
2121  }
2122  };
2123 
2124  template <typename Member>
2125  struct instance_field_invoker
2126  {
2127  template <typename T>
2128  static constexpr auto invoke(T&& target) -> decltype(target.*(Member::pointer))
2129  {
2130  return target.*(Member::pointer);
2131  }
2132 
2133  template <typename T, typename U, typename M = Member, std::enable_if_t<M::is_writable, int> = 0>
2134  static constexpr auto invoke(T&& target, U&& value) -> decltype(target.*(Member::pointer) = std::forward<U>(value))
2135  {
2136  return target.*(Member::pointer) = std::forward<U>(value);
2137  }
2138  };
2139 
2140  template <typename Member>
2141  static_field_invoker<Member> field_type_switch(std::true_type);
2142 
2143  template <typename Member>
2144  instance_field_invoker<Member> field_type_switch(std::false_type);
2145 
2146  template <typename Member>
2147  constexpr decltype(nullptr) get_function_pointer(...)
2148  {
2149  return nullptr;
2150  }
2151 
2152  template <typename Member>
2153  constexpr auto get_function_pointer(int) -> decltype(Member::pointer())
2154  {
2155  return Member::pointer();
2156  }
2157 
2158  template <typename Member, typename Pointer>
2159  constexpr decltype(nullptr) resolve_function_pointer(...)
2160  {
2161  return nullptr;
2162  }
2163 
2164  template <typename Member, typename Pointer>
2165  constexpr auto resolve_function_pointer(int) -> decltype(Member::template resolve<Pointer>())
2166  {
2167  return Member::template resolve<Pointer>();
2168  }
2169 
2170  template <typename T, size_t N>
2171  using make_descriptor = std::conditional_t<refl::trait::is_field_v<refl::detail::member_info<T, N>>,
2172  field_descriptor<T, N>,
2173  std::conditional_t<refl::trait::is_function_v<refl::detail::member_info<T, N>>,
2174  function_descriptor<T, N>,
2175  void
2176  >>;
2177 
2178  template <typename T>
2179  type_list<> enumerate_members(std::index_sequence<>);
2180 
2181  template <typename T, size_t... Idx>
2182  type_list<make_descriptor<T, Idx>...> enumerate_members(std::index_sequence<Idx...>);
2183 
2184  template <typename T>
2185  struct declared_member_list
2186  {
2187  static_assert(refl::trait::is_reflectable_v<T>, "This type does not support reflection!");
2188  using type = decltype(enumerate_members<T>(std::make_index_sequence<refl::detail::type_info<T>::member_count>{}));
2189  };
2190 
2191  template <typename T>
2192  using attribute_types = trait::as_type_list_t<std::remove_cv_t<decltype(refl::detail::type_info<T>::attributes)>>;
2193 
2194  template <typename>
2195  struct flatten;
2196 
2197  template <typename... TypeLists>
2198  struct flatten<type_list<TypeLists...>> : trait::concat<TypeLists...>
2199  {
2200  };
2201 
2202  template <typename T, typename Base>
2203  static constexpr void validate_base()
2204  {
2205  static_assert(std::is_base_of_v<Base, T>, "Base is not a base type of T!");
2206  }
2207 
2208  template <typename T, typename... Bases>
2209  static constexpr void validate_bases(type_list<Bases...>)
2210  {
2211  util::ignore((validate_base<T, Bases>(), 0)...);
2212  }
2213 
2214  template <typename T>
2215  static constexpr auto get_declared_base_type_list()
2216  {
2217  if constexpr (trait::contains_instance_v<attr::base_types, attribute_types<T>>) {
2218  using base_types_type = trait::remove_qualifiers_t<decltype(util::get_instance<attr::base_types>(refl::detail::type_info<T>::attributes))>;
2219  validate_bases<T>(base_types_type::list);
2220  return typename base_types_type::list_type{};
2221  }
2222  else {
2223  return type_list<>{};
2224  }
2225  }
2226 
2227  template <typename T>
2228  struct declared_base_type_list
2229  {
2230  using type = decltype(get_declared_base_type_list<T>());
2231  };
2232 
2233  template <typename T>
2234  struct base_type_list;
2235 
2236  template <typename T>
2237  static constexpr auto get_base_type_list()
2238  {
2239  if constexpr (trait::contains_instance_v<attr::base_types, attribute_types<T>>) {
2240  using declared_bases = typename declared_base_type_list<T>::type;
2241  using rec_bases = typename flatten<trait::map_t<base_type_list, declared_bases>>::type;
2242  return trait::unique_t<trait::concat_t<declared_bases, rec_bases>>{};
2243  }
2244  else {
2245  return type_list<>{};
2246  }
2247  }
2248 
2249  template <typename T>
2250  struct base_type_list
2251  {
2252  using type = decltype(get_base_type_list<T>());
2253  };
2254 
2255  template <typename T>
2256  struct member_list : flatten<trait::map_t<declared_member_list, trait::prepend_t<T, typename base_type_list<T>::type>>>
2257  {
2258  };
2259 
2260  } // namespace detail
2261 
2262  /** A type_list of the declared member descriptors of the target type T. */
2263  template <typename T>
2264  using declared_member_list = typename detail::declared_member_list<T>::type;
2265 
2266  /** A type_list of the declared and inherited member descriptors of the target type T. */
2267  template <typename T>
2268  using member_list = typename detail::member_list<T>::type;
2269 
2270  /**
2271  * @brief The base type for member descriptors.
2272  */
2273  template <typename T, size_t N>
2275  {
2276  protected:
2277 
2278  typedef refl::detail::member_info<T, N> member;
2279 
2280  public:
2281 
2282  /**
2283  * An alias for the declaring type of the reflected member.
2284  *
2285  * \code{.cpp}
2286  * struct Foo { const int* x; };
2287  * REFL_AUTO(type(Foo), field(x))
2288  *
2289  * get_t<0, member_list<Foo>>::declaring_type -> Foo
2290  * \endcode
2291  */
2292  typedef T declaring_type;
2293 
2294  /** An alias specifying the member type of member. */
2295  typedef typename member::member_type member_type;
2296 
2297  /**
2298  * An alias specifying the types of the attributes of the member. (Removes CV-qualifiers.)
2299  * \copydetails refl::descriptor::get_attribute_types
2300  */
2301  typedef trait::as_type_list_t<std::remove_cv_t<decltype(member::attributes)>> attribute_types;
2302 
2303  /**
2304  * The type_descriptor of the declaring type.
2305  * \copydetails refl::descriptor::get_declarator
2306  */
2307  static constexpr type_descriptor<T> declarator{ };
2308 
2309  /**
2310  * The name of the reflected member.
2311  * \copydetails refl::descriptor::get_name
2312  */
2313  static constexpr auto name{ member::name };
2314 
2315  /**
2316  * The attributes of the reflected member.
2317  * \copydetails refl::descriptor::get_attributes
2318  */
2319  static constexpr auto attributes{ member::attributes };
2320 
2321  };
2322 
2323  /**
2324  * @brief Represents a reflected field.
2325  */
2326  template <typename T, size_t N>
2327  class field_descriptor : public member_descriptor_base<T, N>
2328  {
2329  using typename member_descriptor_base<T, N>::member;
2330  static_assert(trait::is_field_v<member>);
2331 
2332  public:
2333 
2334  /**
2335  * Type value type of the member.
2336  *
2337  * \code{.cpp}
2338  * struct Foo { const int* x; };
2339  * REFL_AUTO(type(Foo), field(x))
2340  *
2341  * get_t<0, member_list<Foo>>::value_type -> const int*
2342  * \endcode
2343  */
2344  typedef typename member::value_type value_type;
2345 
2346  /**
2347  * Whether the field is static or not.
2348  * \copydetails refl::descriptor::is_static
2349  */
2350  static constexpr bool is_static{ !std::is_member_object_pointer_v<decltype(member::pointer)> };
2351 
2352  /**
2353  * Whether the field is const or not.
2354  * @see refl::descriptor::is_const
2355  */
2356  static constexpr bool is_writable{ !std::is_const_v<value_type> };
2357 
2358  /**
2359  * A member pointer to the reflected field of the appropriate type.
2360  * \copydetails refl::descriptor::get_pointer
2361  */
2362  static constexpr auto pointer{ member::pointer };
2363 
2364  private:
2365 
2366  using invoker = decltype(detail::field_type_switch<field_descriptor>(std::bool_constant<is_static>{}));
2367 
2368  public:
2369 
2370  /**
2371  * Returns the value of the field. (for static fields).
2372  * \copydetails refl::descriptor::invoke
2373  */
2374  template <decltype(nullptr) = nullptr>
2375  static constexpr decltype(auto) get() noexcept
2376  {
2377  return *member::pointer;
2378  }
2379 
2380  /**
2381  * Returns the value of the field. (for instance fields).
2382  * \copydetails refl::descriptor::invoke
2383  */
2384  template <typename U>
2385  static constexpr decltype(auto) get(U&& target) noexcept
2386  {
2387  return target.*(member::pointer);
2388  }
2389 
2390  /**
2391  * A synonym for get().
2392  * \copydetails refl::descriptor::invoke
2393  */
2394  template <typename... Args>
2395  constexpr auto operator()(Args&&... args) const noexcept -> decltype(invoker::invoke(std::forward<Args>(args)...))
2396  {
2397  return invoker::invoke(std::forward<Args>(args)...);
2398  }
2399 
2400  };
2401 
2402  /**
2403  * @brief Represents a reflected function.
2404  */
2405  template <typename T, size_t N>
2406  class function_descriptor : public member_descriptor_base<T, N>
2407  {
2408  using typename member_descriptor_base<T, N>::member;
2409  static_assert(trait::is_function_v<member>);
2410 
2411  public:
2412 
2413  /**
2414  * Invokes the function with the given arguments.
2415  * If the function is an instance function, a reference
2416  * to the instance is provided as first argument.
2417  * \copydetails refl::descriptor::invoke
2418  */
2419  template <typename... Args>
2420  static constexpr auto invoke(Args&&... args) -> decltype(member::invoke(std::declval<Args>()...))
2421  {
2422  return member::invoke(std::forward<Args>(args)...);
2423  }
2424 
2425  /**
2426  * The return type of an invocation of this member with Args... (as if by invoke(...)).
2427  * \copydetails refl::descriptor::return_type
2428  */
2429  template <typename... Args>
2430  using return_type = decltype(member::invoke(std::declval<Args>()...));
2431 
2432  /**
2433  * A synonym for invoke(args...).
2434  * \copydetails refl::descriptor::invoke
2435  */
2436  template <typename... Args>
2437  constexpr auto operator()(Args&&... args) const -> decltype(invoke(std::declval<Args>()...))
2438  {
2439  return invoke(std::forward<Args>(args)...);
2440  }
2441 
2442  /**
2443  * Returns a pointer to a non-overloaded function.
2444  * \copydetails refl::descriptor::get_pointer
2445  */
2446  static constexpr auto pointer{ detail::get_function_pointer<member>(0) };
2447 
2448  /**
2449  * Whether the pointer member was correctly resolved to a concrete implementation.
2450  * If this field is false, resolve() would need to be called instead.
2451  * \copydetails refl::descriptor::is_resolved
2452  */
2453  static constexpr bool is_resolved{ !std::is_same_v<decltype(pointer), const decltype(nullptr)> };
2454 
2455  /**
2456  * Whether the pointer can be resolved as with the specified type.
2457  * \copydetails refl::descriptor::can_resolve
2458  */
2459  template <typename Pointer>
2460  static constexpr bool can_resolve()
2461  {
2462  return !std::is_same_v<decltype(resolve<Pointer>()), decltype(nullptr)>;
2463  }
2464 
2465  /**
2466  * Resolves the function pointer as being of type Pointer.
2467  * Required when taking a pointer to an overloaded function.
2468  *
2469  * \copydetails refl::descriptor::resolve
2470  */
2471  template <typename Pointer>
2472  static constexpr auto resolve()
2473  {
2474  return detail::resolve_function_pointer<member, Pointer>(0);
2475  }
2476 
2477  };
2478 
2479  /** Represents a reflected type. */
2480  template <typename T>
2481  class type_descriptor
2482  {
2483  private:
2484 
2485  static_assert(refl::trait::is_reflectable_v<T>, "This type does not support reflection!");
2486 
2487  typedef refl::detail::type_info<T> type_info;
2488 
2489  public:
2490 
2491  /**
2492  * The reflected type T.
2493  *
2494  * \code{.cpp}
2495  * struct Foo {};
2496  * REFL_AUTO(type(Foo))
2497  *
2498  * type_descriptor<Foo>::type -> Foo
2499  * \endcode
2500  */
2501  typedef T type;
2502 
2503  /**
2504  * The declared base types (via base_types<Ts...> attribute) of T.
2505  * \copydetails refl::descriptor::get_declared_base_types
2506  */
2507  typedef typename detail::declared_base_type_list<T>::type declared_base_types;
2508 
2509  /**
2510  * The declared and inherited base types of T.
2511  * \copydetails refl::descriptor::get_base_types
2512  */
2513  typedef typename detail::base_type_list<T>::type base_types;
2514 
2515  /**
2516  * A synonym for declared_member_list<T>.
2517  * \copydetails refl::descriptor::declared_member_list
2518  */
2519  typedef declared_member_list<T> declared_member_types;
2520 
2521  /**
2522  * A synonym for member_list<T>.
2523  * \copydetails refl::descriptor::member_list
2524  */
2525  typedef member_list<T> member_types;
2526 
2527  /**
2528  * An alias specifying the types of the attributes of the member. (Removes CV-qualifiers.)
2529  * \copydetails refl::descriptor::get_attribute_types
2530  */
2531  typedef detail::attribute_types<T> attribute_types;
2532 
2533  /**
2534  * The declared base types (via base_types<Ts...> attribute) of T.
2535  * \copydetails refl::descriptor::get_declared_base_types
2536  */
2538 
2539  /**
2540  * The declared and inherited base types of T.
2541  * \copydetails refl::descriptor::get_base_types
2542  */
2543  static constexpr base_types bases{};
2544 
2545  /**
2546  * The list of declared member descriptors.
2547  * \copydetails refl::descriptor::get_declared_members
2548  */
2550 
2551  /**
2552  * The list of declared and inherited member descriptors.
2553  * \copydetails refl::descriptor::get_members
2554  */
2555  static constexpr member_types members{ };
2556 
2557  /**
2558  * The name of the reflected type.
2559  * \copydetails refl::descriptor::get_name
2560  */
2561  static constexpr const auto name{ type_info::name };
2562 
2563  /**
2564  * The attributes of the reflected type.
2565  * \copydetails refl::descriptor::get_attributes
2566  */
2567  static constexpr const auto attributes{ type_info::attributes };
2568 
2569  };
2570 
2571  /**
2572  * Returns the full name of the descriptor
2573  *
2574  * \code{.cpp}
2575  * namespace ns {
2576  * struct Foo {
2577  * int x;
2578  * };
2579  * }
2580  * REFL_AUTO(type(ns::Foo), field(x))
2581  *
2582  * get_name(reflect<Foo>()) -> "ns::Foo"
2583  * get_name(get_t<0, member_list<Foo>>()) -> "x"
2584  * \endcode
2585  */
2586  template <typename Descriptor>
2587  constexpr auto get_name(Descriptor d) noexcept
2588  {
2589  static_assert(trait::is_descriptor_v<Descriptor>);
2590  return d.name;
2591  }
2592 
2593  /**
2594  * Returns a const reference to the descriptor's attribute tuple.
2595  *
2596  * \code{.cpp}
2597  * struct Foo {};
2598  * REFL_AUTO(type(Foo, bases<>, ns::serializable()))
2599  *
2600  * get_attributes(reflect<Foo>()) -> const std::tuple<attr::base_types<>, ns::serializable>&
2601  * \endcode
2602  */
2603  template <typename Descriptor>
2604  constexpr const auto& get_attributes(Descriptor d) noexcept
2605  {
2606  static_assert(trait::is_descriptor_v<Descriptor>);
2607  return d.attributes;
2608  }
2609 
2610  /**
2611  * Returns a type_list of the descriptor's attribute types.
2612  *
2613  * \code{.cpp}
2614  * struct Foo {};
2615  * REFL_AUTO(type(Foo, bases<>, ns::serializable()))
2616  *
2617  * get_attribute_types(reflect<Foo>()) -> type_list<attr::base_types<>, ns::serializable>
2618  * \endcode
2619  */
2620  template <typename Descriptor>
2621  constexpr auto get_attribute_types(Descriptor d) noexcept
2622  {
2623  static_assert(trait::is_descriptor_v<Descriptor>);
2624  return trait::as_type_list_t<std::remove_cv_t<decltype(d.attributes)>>{};
2625  }
2626 
2627  /**
2628  * Returns a type_list of the declared base types of the type.
2629  * Combine with reflect_types to obtain type_descriptors for those types.
2630  * @see reflect_types
2631  *
2632  * \code{.cpp}
2633  * struct Animal {};
2634  * REFL_AUTO(type(Animal))
2635  * struct Mammal : Animal {};
2636  * REFL_AUTO(type(Mammal, bases<Animal>))
2637  * struct Dog : Mammal {}:
2638  * REFL_AUTO(type(Dog, bases<Mammal>))
2639  *
2640  * get_base_types(reflect<Dog>()) -> type_list<Mammal>
2641  * \endcode
2642  */
2643  template <typename TypeDescriptor>
2644  constexpr auto get_declared_base_types(TypeDescriptor t) noexcept
2645  {
2646  static_assert(trait::is_type_v<TypeDescriptor>);
2647  return t.declared_bases;
2648  }
2649 
2650  /**
2651  * Returns a type_list of the declared and inherited base types of the type.
2652  * Combine with reflect_types to obtain type_descriptors for those types.
2653  * @see reflect_types
2654  *
2655  * \code{.cpp}
2656  * struct Animal {};
2657  * REFL_AUTO(type(Animal))
2658  * struct Mammal : Animal {};
2659  * REFL_AUTO(type(Mammal, bases<Animal>))
2660  * struct Dog : Mammal {}:
2661  * REFL_AUTO(type(Dog, bases<Mammal>))
2662  *
2663  * get_base_types(reflect<Dog>()) -> type_list<Mammal, Animal>
2664  * \endcode
2665  */
2666  template <typename TypeDescriptor>
2667  constexpr auto get_base_types(TypeDescriptor t) noexcept
2668  {
2669  static_assert(trait::is_type_v<TypeDescriptor>);
2670  return t.bases;
2671  }
2672 
2673  /**
2674  * Returns a type_list of the declared members of the type.
2675  *
2676  * \code{.cpp}
2677  * struct Base {
2678  * int val;
2679  * };
2680  * struct Foo : Base {
2681  * int bar, baz;
2682  * };
2683  * REFL_AUTO(type(Foo, bases<Base>), field(bar), field(baz))
2684  * get_declared_members(reflect<Foo>()) -> type_list<field_descriptor<Foo, 0> /bar/, field_descriptor<Foo, 1> /baz/>
2685  * \endcode
2686  */
2687  template <typename TypeDescriptor>
2688  constexpr auto get_declared_members(TypeDescriptor t) noexcept
2689  {
2690  static_assert(trait::is_type_v<TypeDescriptor>);
2691  return t.declared_members;
2692  }
2693 
2694  /**
2695  * Returns a type_list of the declared and inherited members of the type.
2696  *
2697  * \code{.cpp}
2698  * struct Base {
2699  * int val;
2700  * };
2701  * struct Foo : Base {
2702  * int bar, baz;
2703  * };
2704  * REFL_AUTO(type(Foo, bases<Base>), field(bar), field(baz))
2705  * get_members(reflect<Foo>()) -> type_list<field_descriptor<Foo, 0> /bar/, field_descriptor<Foo, 1> /baz/, field_descriptor<Base, 0> /val/>
2706  * \endcode
2707  */
2708  template <typename TypeDescriptor>
2709  constexpr auto get_members(TypeDescriptor t) noexcept
2710  {
2711  static_assert(trait::is_type_v<TypeDescriptor>);
2712  return t.members;
2713  }
2714 
2715  /**
2716  * Returns the type_descriptor of declaring type of the member.
2717  *
2718  * \code{.cpp}
2719  * struct Foo {
2720  * int bar;
2721  * };
2722  * REFL_AUTO(type(Foo), field(bar)
2723  * get_declarator(get_t<0, member_list<Foo>>()) -> type_descriptor<Foo>{}
2724  * \endcode
2725  */
2726  template <typename MemberDescriptor>
2727  constexpr auto get_declarator(MemberDescriptor d) noexcept
2728  {
2729  static_assert(trait::is_member_v<MemberDescriptor>);
2730  return d.declarator;
2731  }
2732 
2733  /**
2734  * Returns a pointer to the reflected field/function.
2735  * When the member is a function, the return value might be nullptr
2736  * if the type of the function pointer cannot be resolved.
2737  * @see is_resolved
2738  * @see can_resolve
2739  * @see resolve
2740  *
2741  * \code{.cpp}
2742  * struct Foo {
2743  * int bar;
2744  * static int baz;
2745  * };
2746  * REFL_AUTO(type(Foo), field(bar), field(baz))
2747  * get_pointer(get_t<0, member_list<Foo>>()) -> (int Foo::*) &Foo::bar
2748  * get_pointer(get_t<1, member_list<Foo>>()) -> (int*) &Foo::baz
2749  * \endcode
2750  */
2751  template <typename MemberDescriptor>
2752  constexpr auto get_pointer(MemberDescriptor d) noexcept
2753  {
2754  static_assert(trait::is_member_v<MemberDescriptor>);
2755  return d.pointer;
2756  }
2757 
2758  /**
2759  * Invokes the member with the specified arguments.
2760  *
2761  * \code{.cpp}
2762  * struct Foo {
2763  * int bar = 1;
2764  * static int baz = 5;
2765  * void foobar(int x) { return x * 2; }
2766  * static void foobaz(int x) { return x * 3; }
2767  * };
2768  * REFL_AUTO(type(Foo), field(bar), field(baz), func(foobar), func(foobaz))
2769  * invoke(get_t<0, member_list<Foo>(), Foo()) -> 1 (Foo().bar)
2770  * invoke(get_t<1, member_list<Foo>>()) -> 5 (Foo::baz)
2771  * invoke(get_t<2, member_list<Foo>(), Foo(), 10) -> 20 (Foo().foobar())
2772  * invoke(get_t<3, member_list<Foo>>()) -> 30 (Foo::foobaz())
2773  * \endcode
2774  */
2775  template <typename MemberDescriptor, typename... Args>
2776  constexpr auto invoke(MemberDescriptor d, Args&&... args) noexcept -> decltype(d(std::forward<Args>(args)...))
2777  {
2778  return d(std::forward<Args>(args)...);
2779  }
2780 
2781  /**
2782  * Checks whether the field is declared as static.
2783  *
2784  * \code{.cpp}
2785  * struct Foo {
2786  * int bar;
2787  * static int baz;
2788  * };
2789  * REFL_AUTO(type(Foo), field(bar), field(baz))
2790  * is_static(get_t<0, member_list<Foo>>()) -> false
2791  * is_static(get_t<1, member_list<Foo>>()) -> true
2792  * \endcode
2793  */
2794  template <typename FieldDescriptor>
2795  constexpr auto is_static(FieldDescriptor d) noexcept
2796  {
2797  static_assert(trait::is_field_v<FieldDescriptor>);
2798  return d.is_static;
2799  }
2800 
2801  /**
2802  * Checks whether the value type of the field is const-qualified.
2803  *
2804  * \code{.cpp}
2805  * struct Foo {
2806  * int bar;
2807  * const int baz;
2808  * };
2809  * REFL_AUTO(type(Foo), field(bar), field(baz))
2810  * is_const(get_t<0, member_list<Foo>>()) -> false
2811  * is_const(get_t<1, member_list<Foo>>()) -> true
2812  * \endcode
2813  */
2814  template <typename FieldDescriptor>
2815  constexpr auto is_const(FieldDescriptor d) noexcept
2816  {
2817  static_assert(trait::is_field_v<FieldDescriptor>);
2818  return d.is_const;
2819  }
2820 
2821  /**
2822  * The return type when invoking the specified descriptor using the provided argument types.
2823  * Argument coversion will be applied as per C++ rules.
2824  */
2825  template <typename FunctionDescriptor, typename... Args>
2826  using result_type = typename FunctionDescriptor::template result_type<Args...>;
2827 
2828  /**
2829  * Checks whether the function pointer was automatically resolved.
2830  *
2831  * \code{.cpp}
2832  * struct Foo {
2833  * void bar();
2834  * void bar(int);
2835  * void baz();
2836  * };
2837  * REFL_AUTO(type(Foo), func(bar), func(baz))
2838  * is_resolved(get_t<0, member_list<Foo>>()) -> false
2839  * is_resolved(get_t<1, member_list<Foo>>()) -> true
2840  * \endcode
2841  */
2842  template <typename FunctionDescriptor>
2843  constexpr auto is_resolved(FunctionDescriptor d) noexcept
2844  {
2845  static_assert(trait::is_function_v<FunctionDescriptor>);
2846  return d.is_resolved;
2847  }
2848 
2849  /**
2850  * Checks whether the function pointer can be resolved as
2851  * a pointer of the specified type.
2852  *
2853  * \code{.cpp}
2854  * struct Foo {
2855  * void bar();
2856  * void bar(int);
2857  * };
2858  * REFL_AUTO(type(Foo), func(bar))
2859  * can_resolve<void(Foo::*)()>(get_t<0, member_list<Foo>>()) -> true
2860  * can_resolve<void(Foo::*)(int)>(get_t<0, member_list<Foo>>()) -> true
2861  * can_resolve<void(Foo::*)(std::string)>(get_t<0, member_list<Foo>>()) -> false
2862  * \endcode
2863  */
2864  template <typename Pointer, typename FunctionDescriptor>
2865  constexpr auto can_resolve(FunctionDescriptor d) noexcept
2866  {
2867  static_assert(trait::is_function_v<FunctionDescriptor>);
2868  return d.template can_resolve<Pointer>();
2869  }
2870 
2871  /**
2872  * Resolves the function pointer as a pointer of the specified type.
2873  *
2874  * \code{.cpp}
2875  * struct Foo {
2876  * void bar();
2877  * void bar(int);
2878  * };
2879  * REFL_AUTO(type(Foo), func(bar))
2880  * resolve<void(Foo::*)()>(get_t<0, member_list<Foo>>()) -> <&Foo::bar()>
2881  * resolve<void(Foo::*)(int)>(get_t<0, member_list<Foo>>()) -> <&Foo::bar(int)>
2882  * resolve<void(Foo::*)(std::string)>(get_t<0, member_list<Foo>>()) -> nullptr
2883  * \endcode
2884  */
2885  template <typename Pointer, typename FunctionDescriptor>
2886  constexpr auto resolve(FunctionDescriptor d) noexcept
2887  {
2888  static_assert(trait::is_function_v<FunctionDescriptor>);
2889  return d.template resolve<Pointer>();
2890  }
2891 
2892  /**
2893  * Checks whether T is a field descriptor.
2894  *
2895  * @see refl::descriptor::field_descriptor
2896  *
2897  * \code{.cpp}
2898  * REFL_AUTO(type(Foo), func(bar), field(baz))
2899  * is_function(get_t<0, member_list<Foo>>()) -> false
2900  * is_function(get_t<1, member_list<Foo>>()) -> true
2901  * \endcode
2902  */
2903  template <typename Descriptor>
2904  constexpr bool is_field(Descriptor) noexcept
2905  {
2906  static_assert(trait::is_descriptor_v<Descriptor>);
2907  return trait::is_field_v<Descriptor>;
2908  }
2909 
2910  /**
2911  * Checks whether T is a function descriptor.
2912  *
2913  * @see refl::descriptor::function_descriptor
2914  *
2915  * \code{.cpp}
2916  * REFL_AUTO(type(Foo), func(bar), field(baz))
2917  * is_function(get_t<0, member_list<Foo>>()) -> true
2918  * is_function(get_t<1, member_list<Foo>>()) -> false
2919  * \endcode
2920  */
2921  template <typename Descriptor>
2922  constexpr bool is_function(Descriptor) noexcept
2923  {
2924  static_assert(trait::is_descriptor_v<Descriptor>);
2925  return trait::is_function_v<Descriptor>;
2926  }
2927 
2928  /**
2929  * Checks whether T is a type descriptor.
2930  *
2931  * @see refl::descriptor::type_descriptor
2932  *
2933  * \code{.cpp}
2934  * REFL_AUTO(type(Foo))
2935  * is_type(reflect<Foo>>()) -> true
2936  * \endcode
2937  */
2938  template <typename Descriptor>
2939  constexpr bool is_type(Descriptor) noexcept
2940  {
2941  static_assert(trait::is_descriptor_v<Descriptor>);
2942  return trait::is_type_v<Descriptor>;
2943  }
2944 
2945  /**
2946  * Checks whether T has an attribute of type A.
2947  *
2948  * \code{.cpp}
2949  * REFL_AUTO(type(User), func(get_name, property()), func(set_name, property()))
2950  * has_attribute<attr::property>(get_t<0, member_list<User>>{}) -> true
2951  * \endcode
2952  */
2953  template <typename A, typename Descriptor>
2954  constexpr bool has_attribute(Descriptor) noexcept
2955  {
2956  static_assert(trait::is_descriptor_v<Descriptor>);
2957  return trait::contains_base_v<A, typename Descriptor::attribute_types>;
2958  }
2959 
2960  /**
2961  * Checks whether T has an attribute of that is a template instance of A.
2962  *
2963  * \code{.cpp}
2964  * REFL_AUTO(type(Random, debug{ [](auto os, auto){ os << "[Random]"; } }))
2965  * has_attribute<attr::debug>(reflect<Random>()) -> true
2966  * \endcode
2967  */
2968  template <template<typename...> typename A, typename Descriptor>
2969  constexpr bool has_attribute(Descriptor) noexcept
2970  {
2971  static_assert(trait::is_descriptor_v<Descriptor>);
2972  return trait::contains_instance_v<A, typename Descriptor::attribute_types>;
2973  }
2974 
2975  /**
2976  * Returns the value of the attribute A on T.
2977  *
2978  * \code{.cpp}
2979  * REFL_AUTO(type(User), func(get_name, property()), func(set_name, property()))
2980  * get_attribute<attr::property>(get_t<0, member_list<User>>{}) -> property{ friendly_name = nullopt }
2981  * \endcode
2982  */
2983  template <typename A, typename Descriptor>
2984  constexpr const A& get_attribute(Descriptor d) noexcept
2985  {
2986  static_assert(trait::is_descriptor_v<Descriptor>);
2987  return util::get<A>(d.attributes);
2988  }
2989 
2990  /**
2991  * Returns the value of the attribute A on T.
2992  *
2993  * \code{.cpp}
2994  * REFL_AUTO(type(Random, debug{ [](auto os, auto){ os << "[Random]"; } }))
2995  * get_attribute<attr::debug>(reflect<Random>()) -> instance of debug<LambdaType>
2996  * \endcode
2997  */
2998  template <template<typename...> typename A, typename Descriptor>
2999  constexpr const auto& get_attribute(Descriptor d) noexcept
3000  {
3001  static_assert(trait::is_descriptor_v<Descriptor>);
3002  return util::get_instance<A>(d.attributes);
3003  }
3004 
3005  /**
3006  * Checks whether T is a member descriptor marked with the property attribute.
3007  *
3008  * @see refl::attr::property
3009  * @see refl::descriptor::get_property
3010  *
3011  * \code{.cpp}
3012  * REFL_AUTO(type(User), func(get_name, property("user_name")), func(set_name, property()))
3013  * is_property(get_t<0, member_list<User>>{}) -> true
3014  * \endcode
3015  */
3016  template <typename MemberDescriptor>
3017  constexpr bool is_property(MemberDescriptor d) noexcept
3018  {
3019  static_assert(trait::is_member_v<MemberDescriptor>);
3020  return has_attribute<attr::property>(d);
3021  }
3022 
3023  /**
3024  * Gets the property attribute.
3025  *
3026  * @see refl::attr::property
3027  * @see refl::descriptor::is_property
3028  *
3029  * \code{.cpp}
3030  * REFL_AUTO(type(User), func(get_name, property("user_name")), func(set_name, property()))
3031  * *get_property(get_t<0, member_list<User>>{}).friendly_name -> "user_name"
3032  * \endcode
3033  */
3034  template <typename FunctionDescriptor>
3035  constexpr attr::property get_property(FunctionDescriptor d) noexcept
3036  {
3037  static_assert(trait::is_function_v<FunctionDescriptor>);
3038  return get_attribute<attr::property>(d);
3039  }
3040 
3041  namespace detail
3042  {
3043  struct placeholder
3044  {
3045  template <typename T>
3046  operator T() const;
3047  };
3048  } // namespace detail
3049 
3050  /**
3051  * Checks if T is a 0-arg const-qualified member function with a property attribute or a field.
3052  *
3053  * \code{.cpp}
3054  * REFL_AUTO(type(User), func(get_name, property()), func(set_name, property()))
3055  * is_readable(get_t<0, member_list<User>>{}) -> true
3056  * is_readable(get_t<1, member_list<User>>{}) -> false
3057  * \endcode
3058  */
3059  template <typename MemberDescriptor>
3060  constexpr bool is_readable(MemberDescriptor) noexcept
3061  {
3062  static_assert(trait::is_member_v<MemberDescriptor>);
3063  if constexpr (trait::is_property_v<MemberDescriptor>) {
3064  if constexpr (std::is_invocable_v<MemberDescriptor, const typename MemberDescriptor::declaring_type&>) {
3065  using return_type = typename MemberDescriptor::template return_type<const typename MemberDescriptor::declaring_type&>;
3066  return !std::is_void_v<return_type>;
3067  }
3068  else {
3069  return false;
3070  }
3071  }
3072  else {
3073  return trait::is_field_v<MemberDescriptor>;
3074  }
3075  }
3076 
3077  /**
3078  * Checks if T is a 1-arg non-const-qualified member function with a property attribute or a non-const field.
3079  *
3080  * \code{.cpp}
3081  * struct User { std::string get_name() const; }
3082  * REFL_AUTO(type(User), func(get_name, property()), func(set_name, property()))
3083  * is_writable(get_t<0, member_list<User>>{}) -> false
3084  * is_writable(get_t<1, member_list<User>>{}) -> true
3085  * \endcode
3086  */
3087  template <typename MemberDescriptor>
3088  constexpr bool is_writable(MemberDescriptor) noexcept
3089  {
3090  static_assert(trait::is_member_v<MemberDescriptor>);
3091  if constexpr (trait::is_property_v<MemberDescriptor>) {
3092  return std::is_invocable_v<MemberDescriptor, typename MemberDescriptor::declaring_type&, detail::placeholder>;
3093  }
3094  else if constexpr (trait::is_field_v<MemberDescriptor>) {
3095  return !std::is_const_v<typename trait::remove_qualifiers_t<MemberDescriptor>::value_type>;
3096  }
3097  else {
3098  return false;
3099  }
3100  }
3101 
3102  namespace detail
3103  {
3104  template <typename T>
3105  struct get_type_descriptor
3106  {
3107  typedef type_descriptor<T> type;
3108  };
3109  } // namespace detail
3110 
3111  /**
3112  * Checks if a type has a bases attribute.
3113  *
3114  * @deprecated Use has_base_types in combination with reflect_types instead.
3115  * @see refl::attr::bases
3116  * @see refl::descriptor::get_bases
3117  *
3118  * \code{.cpp}
3119  * REFL_AUTO(type(Dog, bases<Animal>))
3120  * has_bases(reflect<Dog>()) -> true
3121  * \endcode
3122  */
3123  template <typename TypeDescriptor>
3124  [[deprecated]] constexpr auto has_bases(TypeDescriptor t) noexcept
3125  {
3126  static_assert(trait::is_type_v<TypeDescriptor>);
3127  return has_attribute<attr::base_types>(t);
3128  }
3129 
3130  /**
3131  * Returns a list of the type_descriptor<T>s of the base types of the target,
3132  * as specified by the bases<A, B, ...> attribute.
3133  *
3134  * @deprecated Use get_base_types in combination with reflect_types instead.
3135  * @see refl::attr::bases
3136  * @see refl::descriptor::has_bases
3137  *
3138  * \code{.cpp}
3139  * REFL_AUTO(type(Dog, bases<Animal>))
3140  * get_bases(reflect<Dog>()) -> type_list<type_descriptor<Animal>>
3141  * \endcode
3142  */
3143  template <typename TypeDescriptor>
3144  [[deprecated]] constexpr auto get_bases(TypeDescriptor t) noexcept
3145  {
3146  static_assert(trait::is_type_v<TypeDescriptor>);
3147  static_assert(has_bases(t), "Target type does not have a bases<A, B, ...> attribute.");
3148 
3149  constexpr auto bases = get_attribute<attr::base_types>(t);
3150  using base_types = typename decltype(bases)::list_type;
3151  return trait::map_t<detail::get_type_descriptor, base_types>{};
3152  }
3153 
3154  /**
3155  * Returns the unqualified name of the type, discarding the namespace and typenames (if a template type).
3156  *
3157  * \code{.cpp}
3158  * get_simple_name(reflect<std::vector<float>>()) -> "vector"
3159  * \endcode
3160  */
3161  template <typename TypeDescriptor>
3162  constexpr auto get_simple_name(TypeDescriptor t)
3163  {
3164  static_assert(trait::is_type_v<TypeDescriptor>);
3165  constexpr size_t template_start = t.name.find('<');
3166  constexpr size_t scope_last = t.name.rfind(':', template_start);
3167  if constexpr (scope_last == const_string<0>::npos) {
3168  return t.name;
3169  }
3170  else {
3171  return t.name.template substr<scope_last + 1, template_start - scope_last - 1>();
3172  }
3173  }
3174 
3175  /**
3176  * Returns the debug name of T (In the form of 'declaring_type::member_name') as a const_string.
3177  *
3178  * \code{.cpp}
3179  * REFL_AUTO(type(Point), field(x), field(y))
3180  * get_debug_name_const(get_t<0, member_list<Point>>{}) -> "Point::x"
3181  * \endcode
3182  */
3183  template <typename MemberDescriptor>
3184  constexpr auto get_debug_name_const(MemberDescriptor d)
3185  {
3186  static_assert(trait::is_member_v<MemberDescriptor>);
3187  return d.declarator.name + "::" + d.name;
3188  }
3189 
3190  /**
3191  * Returns the debug name of T. (In the form of 'declaring_type::member_name').
3192  * \code{.cpp}
3193  * REFL_AUTO(type(Point), field(x), field(y))
3194  * get_debug_name(get_t<0, member_list<Point>>{}) -> "Point::x"
3195  * \endcode
3196  */
3197  template <typename MemberDescriptor>
3198  const char* get_debug_name(MemberDescriptor d)
3199  {
3200  static_assert(trait::is_member_v<MemberDescriptor>);
3201  static const std::string name(get_debug_name_const(d).str());
3202  return name.c_str();
3203  }
3204 
3205  namespace detail
3206  {
3207  constexpr bool is_upper(char ch)
3208  {
3209  return ch >= 'A' && ch <= 'Z';
3210  }
3211 
3212  constexpr char to_upper(char ch)
3213  {
3214  return ch >= 'a' && ch <= 'z'
3215  ? char(ch + ('A' - 'a'))
3216  : ch;
3217  }
3218 
3219  constexpr char to_lower(char ch)
3220  {
3221  return ch >= 'A' && ch <= 'Z'
3222  ? char(ch + ('a' - 'A'))
3223  : ch;
3224  }
3225 
3226  template <typename T, bool PreferUpper>
3227  constexpr auto normalize_bare_accessor_name()
3228  {
3229  constexpr auto str = T::name.template substr<3>();
3230  if constexpr (str.data[0] == '_') {
3231  return str.template substr<1>();
3232  }
3233  else if constexpr (!PreferUpper && str.data[0] >= 'A' && str.data[0] <= 'Z') {
3234  return make_const_string(to_lower(str.data[0])) + str.template substr<1>();
3235  }
3236  else if constexpr (PreferUpper) {
3237  return make_const_string(to_upper(str.data[0])) + str.template substr<1>();
3238  }
3239  else {
3240  return str;
3241  }
3242  }
3243 
3244  template <typename T>
3245  constexpr auto normalize_accessor_name(const T)
3246  {
3247  constexpr T t{};
3248  if constexpr (t.name.size > 3) {
3249  constexpr auto prefix = t.name.template substr<0, 3>();
3250  constexpr bool cont_snake_or_camel = (t.name.size > 4 && t.name.data[3] == '_' && !is_upper(t.name.data[4])) || is_upper(t.name.data[3]);
3251  constexpr bool cont_pascal = is_upper(t.name.data[3]);
3252 
3253  if constexpr ((is_readable(T{}) && ((prefix == "Get" && cont_pascal) || (prefix == "get" && cont_snake_or_camel)))
3254  || (is_writable(T{}) && ((prefix == "Set" && cont_pascal) || (prefix == "set" && cont_snake_or_camel)))) {
3255  constexpr bool prefer_upper = is_upper(prefix.data[0]);
3256  return normalize_bare_accessor_name<T, prefer_upper>();
3257  }
3258  else {
3259  return t.name;
3260  }
3261  }
3262  else {
3263  return t.name;
3264  }
3265  }
3266 
3267  template <typename T>
3268  constexpr auto get_display_name(const T t) noexcept
3269  {
3270  if constexpr (trait::is_property_v<T>) {
3271  if constexpr (util::get<attr::property>(t.attributes).friendly_name) {
3272  return REFL_MAKE_CONST_STRING(*util::get<attr::property>(t.attributes).friendly_name);
3273  }
3274  else {
3275  return detail::normalize_accessor_name(t);
3276  }
3277  }
3278  else {
3279  return t.name;
3280  }
3281  }
3282  } // namespace detail
3283 
3284  /**
3285  * Returns the display name of T.
3286  * Uses the friendly_name of the property attribute, or the normalized name if no friendly_name was provided.
3287  *
3288  * \code{.cpp}
3289  * struct Foo {
3290  * int get_foo() const;
3291  * int GetFoo() const;
3292  * int get_non_const() /missing const/;
3293  * int get_custom() const;
3294  * };
3295  * REFL_AUTO(
3296  * type(Foo),
3297  * func(get_foo, property()),
3298  * func(GetFoo, property()),
3299  * func(get_non_const, property()),
3300  * func(get_custom, property("value")),
3301  * )
3302  *
3303  * get_display_name(get_t<0, member_list<Foo>>{}) -> "foo"
3304  * get_display_name(get_t<1, member_list<Foo>>{}) -> "Foo"
3305  * get_display_name(get_t<2, member_list<Foo>>{}) -> "get_non_const"
3306  * get_display_name(get_t<3, member_list<Foo>>{}) -> "value"
3307  * \endcode
3308  */
3309  template <typename Descriptor>
3310  const char* get_display_name(Descriptor d) noexcept
3311  {
3312  static_assert(trait::is_descriptor_v<Descriptor>);
3313  static const std::string name(detail::get_display_name(d));
3314  return name.c_str();
3315  }
3316 
3317  /**
3318  * Returns the display name of T as a const_string<N>.
3319  * Uses the friendly_name of the property attribute, or the normalized name if no friendly_name was provided.
3320  * @see get_display_name
3321  */
3322  template <typename Descriptor>
3323  constexpr auto get_display_name_const(Descriptor d) noexcept
3324  {
3325  static_assert(trait::is_descriptor_v<Descriptor>);
3326  return detail::get_display_name(d);
3327  }
3328 
3329  /**
3330  * Checks if there exists a member that has the same display name as the one provied and is writable.
3331  * For getter methods with a property attribute, the return value will be true if there exists a
3332  * reflected setter method with a property with the same display name (property name normalization applies automatically).
3333  * For fields, returns true only if the field is writable.
3334  */
3335  template <typename ReadableMember>
3336  constexpr auto has_writer(ReadableMember member)
3337  {
3338  static_assert(is_writable(member) || is_property(member));
3339  if constexpr (is_writable(member)) {
3340  return true;
3341  }
3342  else {
3343  return contains(get_declarator(member).members, [](auto m) {
3344  return is_property(m) && is_writable(m) && get_display_name_const(m) == get_display_name_const(ReadableMember{});
3345  });
3346  }
3347  }
3348 
3349  /**
3350  * Checks if there exists a member that has the same display name as the one provied and is readable.
3351  * For setter methods with a property attribute, the return value will be true if there exists a
3352  * reflected getter method with a property with the same display name (property name normalization applies automatically).
3353  * For fields, returns true.
3354  */
3355  template <typename WritableMember>
3356  constexpr auto has_reader(WritableMember member)
3357  {
3358  static_assert(is_readable(member) || is_property(member));
3359  if constexpr (is_readable(member)) {
3360  return true;
3361  }
3362  else {
3363  return contains(get_declarator(member).members, [](auto m) {
3364  return is_property(m) && is_readable(m) && get_display_name_const(m) == get_display_name_const(WritableMember{});
3365  });
3366  }
3367  }
3368 
3369  /**
3370  * Returns a member that has the same display name as the one provied and is writable.
3371  * For getter methods with a property attribute, the return value will the
3372  * reflected setter method with a property with the same display name (property name normalization applies automatically).
3373  * For fields, returns the same descriptor if writable.
3374  */
3375  template <typename ReadableMember>
3376  constexpr auto get_writer(ReadableMember member)
3377  {
3378  static_assert(is_writable(member) || is_property(member));
3379  if constexpr (is_writable(member)) {
3380  return member;
3381  }
3382  else {
3383  static_assert(has_writer(member));
3384  return find_one(get_declarator(member).members, [](auto m) {
3385  return is_property(m) && is_writable(m) && get_display_name_const(m) == get_display_name_const(ReadableMember{});
3386  });
3387  }
3388  }
3389 
3390  /**
3391  * Returns a member that has the same display name as the one provied and is readable.
3392  * For setter methods with a property attribute, the return value will be a
3393  * reflected getter method with a property with the same display name (property name normalization applies automatically).
3394  * For fields, returns the same descriptor.
3395  */
3396  template <typename WritableMember>
3397  constexpr auto get_reader(WritableMember member)
3398  {
3399  static_assert(is_readable(member) || is_property(member));
3400  if constexpr (is_readable(member)) {
3401  return member;
3402  }
3403  else {
3404  static_assert(has_reader(member));
3405  return find_one(get_declarator(member).members, [](auto m) {
3406  return is_property(m) && is_readable(m) && get_display_name_const(m) == get_display_name_const(WritableMember{});
3407  });
3408  }
3409  }
3410 
3411  } // namespace descriptor
3412 
3413  using descriptor::member_list;
3414  using descriptor::declared_member_list;
3415  using descriptor::field_descriptor;
3416  using descriptor::function_descriptor;
3417  using descriptor::type_descriptor;
3418 
3419  /** Returns true if the type T is reflectable. */
3420  template <typename T>
3421  constexpr bool is_reflectable() noexcept
3422  {
3423  return trait::is_reflectable_v<T>;
3424  }
3425 
3426  /** Returns true if the non-qualified type T is reflectable.*/
3427  template <typename T>
3428  constexpr bool is_reflectable(const T&) noexcept
3429  {
3430  return trait::is_reflectable_v<T>;
3431  }
3432 
3433  /** Returns the type descriptor for the type T. */
3434  template<typename T>
3435  constexpr type_descriptor<T> reflect() noexcept
3436  {
3437  return {};
3438  }
3439 
3440  /** Returns the type descriptor for the non-qualified type T. */
3441  template<typename T>
3442  constexpr type_descriptor<T> reflect(const T&) noexcept
3443  {
3444  return {};
3445  }
3446 
3447 #ifndef REFL_DETAIL_FORCE_EBO
3448 #ifdef _MSC_VER
3449 #define REFL_DETAIL_FORCE_EBO __declspec(empty_bases)
3450 #else
3451 #define REFL_DETAIL_FORCE_EBO
3452 #endif
3453 #endif
3454 
3455  /**
3456  * @brief Contains utilities that can have runtime-overhead (like proxy, debug, invoke)
3457  */
3458  namespace runtime
3459  {
3460  template <typename Derived, typename Target>
3462 
3463  namespace detail
3464  {
3465  template <typename T>
3466  struct get_member_info;
3467 
3468  template <typename T, size_t N>
3469  struct get_member_info<refl::function_descriptor<T, N>>
3470  {
3471  using type = refl::detail::member_info<T, N>;
3472  };
3473 
3474  template <typename T, size_t N>
3475  struct get_member_info<refl::field_descriptor<T, N>>
3476  {
3477  using type = refl::detail::member_info<T, N>;
3478  };
3479 
3480  template <typename T, typename U>
3481  constexpr T& static_ref_cast(U& value) noexcept
3482  {
3483  return static_cast<T&>(value);
3484  }
3485 
3486  template <typename T, typename U>
3487  constexpr const T& static_ref_cast(const U& value) noexcept
3488  {
3489  return static_cast<const T&>(value);
3490  }
3491 
3492  template <typename... Results>
3493  constexpr type_list<Results...> get_members_skip_shadowed(type_list<>, type_list<Results...>)
3494  {
3495  return {};
3496  }
3497 
3498  template <typename Member, typename... Members, typename... Results>
3499  constexpr auto get_members_skip_shadowed(type_list<Member, Members...>, type_list<Results...>)
3500  {
3501  if constexpr ((... || (Results::name == Member::name))) {
3502  return get_members_skip_shadowed(type_list<Members...>{}, type_list<Results...>{});
3503  }
3504  else {
3505  return get_members_skip_shadowed(type_list<Members...>{}, type_list<Results..., Member>{});
3506  }
3507  }
3508 
3509  template <typename T>
3510  using members_skip_shadowed = decltype(get_members_skip_shadowed(member_list<T>{}, type_list<>{}));
3511 
3512  /** Implements a proxy for a reflected function. */
3513  template <typename Derived, typename Func>
3514  struct REFL_DETAIL_FORCE_EBO function_proxy : public get_member_info<Func>::type::template remap<function_proxy<Derived, Func>>
3515  {
3516  function_proxy()
3517  {
3518  }
3519 
3520  template <typename Self, typename... Args>
3521  static constexpr decltype(auto) invoke_impl(Self&& self, Args&& ... args)
3522  {
3523  return Derived::template invoke_impl<Func>(static_ref_cast<Derived>(self), std::forward<Args>(args)...);
3524  }
3525  };
3526 
3527  template <typename, typename>
3528  struct REFL_DETAIL_FORCE_EBO function_proxies;
3529 
3530  /** Implements a proxy for all reflected functions. */
3531  template <typename Derived, typename... Members>
3532  struct REFL_DETAIL_FORCE_EBO function_proxies<Derived, type_list<Members...>> : public function_proxy<Derived, Members>...
3533  {
3534  };
3535 
3536  /** Implements a proxy for a reflected field. */
3537  template <typename Derived, typename Field>
3538  struct REFL_DETAIL_FORCE_EBO field_proxy : public get_member_info<Field>::type::template remap<field_proxy<Derived, Field>>
3539  {
3540  field_proxy()
3541  {
3542  }
3543 
3544  template <typename Self, typename... Args>
3545  static constexpr decltype(auto) invoke_impl(Self&& self, Args&& ... args)
3546  {
3547  return Derived::template invoke_impl<Field>(static_ref_cast<Derived>(self), std::forward<Args>(args)...);
3548  }
3549  };
3550 
3551 
3552  template <typename, typename>
3553  struct REFL_DETAIL_FORCE_EBO field_proxies;
3554 
3555  /** Implements a proxy for all reflected fields. */
3556  template <typename Derived, typename... Members>
3557  struct REFL_DETAIL_FORCE_EBO field_proxies<Derived, type_list<Members...>> : public field_proxy<Derived, Members>...
3558  {
3559  };
3560 
3561  template <typename T>
3562  using functions = trait::filter_t<trait::is_function, members_skip_shadowed<T>>;
3563 
3564  template <typename T>
3565  using fields = trait::filter_t<trait::is_field, members_skip_shadowed<T>>;
3566 
3567  } // namespace detail
3568 
3569  /**
3570  * @brief A proxy object that has a static interface identical to the reflected functions and fields of the target.
3571  *
3572  * A proxy object that has a static interface identical to the reflected functions and fields of the target.
3573  * Users should inherit from this class and specify an invoke_impl(Member member, Args&&... args) function.
3574  *
3575  * # Examples:
3576  * \code{.cpp}
3577  * template <typename T>
3578  * struct dummy_proxy : refl::runtime::proxy<dummy_proxy<T>, T> {
3579  * template <typename Member, typename Self, typename... Args>
3580  * static int invoke_impl(Self&& self, Args&&... args) {
3581  * std::cout << get_debug_name(Member()) << " called with " << sizeof...(Args) << " parameters!\n";
3582  * return 0;
3583  * }
3584  * };
3585  * \endcode
3586  */
3587  template <typename Derived, typename Target>
3589  : public detail::function_proxies<proxy<Derived, Target>, detail::functions<Target>>
3590  , public detail::field_proxies<proxy<Derived, Target>, detail::fields<Target>>
3591  {
3592  static_assert(
3593  sizeof(detail::function_proxies<proxy<Derived, Target>, detail::functions<Target>>) == 1 &&
3594  sizeof(detail::field_proxies<proxy<Derived, Target>, detail::fields<Target>>) == 1,
3595  "Multiple inheritance EBO did not kick in! "
3596  "You could try defining the REFL_DETAIL_FORCE_EBO macro appropriately to enable it on the required types. "
3597  "Default for MSC is `__declspec(empty_bases)`.");
3598 
3599  static_assert(
3600  trait::is_reflectable_v<Target>,
3601  "Target type must be reflectable!");
3602 
3603  typedef Target target_type;
3604 
3605  constexpr proxy() noexcept {}
3606 
3607  private:
3608 
3609  template <typename P, typename F>
3610  friend struct detail::function_proxy;
3611 
3612  template <typename P, typename F>
3613  friend struct detail::field_proxy;
3614 
3615  // Called by one of the function_proxy/field_proxy bases.
3616  template <typename Member, typename Self, typename... Args>
3617  static constexpr decltype(auto) invoke_impl(Self&& self, Args&& ... args)
3618  {
3619  return Derived::template invoke_impl<Member>(detail::static_ref_cast<Derived>(self), std::forward<Args>(args)...);
3620  }
3621 
3622  };
3623 
3624  } // namespace runtime
3625 
3626  namespace trait
3627  {
3628  template <typename>
3629  struct is_proxy;
3630 
3631  template <typename T>
3632  struct is_proxy
3633  {
3634  private:
3635  template <typename Derived, typename Target>
3636  static std::true_type test(runtime::proxy<Derived, Target>*);
3637  static std::false_type test(...);
3638  public:
3639  static constexpr bool value{ !std::is_reference_v<T> && decltype(test(std::declval<remove_qualifiers_t<T>*>()))::value };
3640  };
3641 
3642  template <typename T>
3643  [[maybe_unused]] static constexpr bool is_proxy_v{ is_proxy<T>::value };
3644  }
3645 
3646  namespace runtime
3647  {
3648  template <typename CharT, typename T>
3649  void debug(std::basic_ostream<CharT>& os, const T& value, bool compact = false);
3650 
3651  namespace detail
3652  {
3653  template <typename CharT, typename T, typename = decltype(std::declval<std::basic_ostream<CharT>&>() << std::declval<T>())>
3654  std::true_type is_ostream_printable_test(int);
3655 
3656  template <typename CharT, typename T>
3657  std::false_type is_ostream_printable_test(...);
3658 
3659  template <typename CharT, typename T>
3660  constexpr bool is_ostream_printable_v{ decltype(is_ostream_printable_test<CharT, T>(0))::value };
3661 
3662  namespace
3663  {
3664  [[maybe_unused]] int next_depth(int depth)
3665  {
3666  return depth == -1 || depth > 8
3667  ? -1
3668  : depth + 1;
3669  }
3670  }
3671 
3672  template <typename CharT>
3673  void indent(std::basic_ostream<CharT>& os, int depth)
3674  {
3675  for (int i = 0; i < depth; i++) {
3676  os << " ";
3677  }
3678  }
3679 
3680  template <typename CharT, typename T>
3681  void debug_impl(std::basic_ostream<CharT>& os, const T& value, [[maybe_unused]] int depth);
3682 
3683  template <typename CharT, typename T>
3684  void debug_detailed(std::basic_ostream<CharT>& os, const T& value, int depth)
3685  {
3686  using type_descriptor = type_descriptor<T>;
3687  bool compact = depth == -1;
3688  // print type with members enclosed in braces
3689  os << type_descriptor::name << " { ";
3690  if (!compact) os << '\n';
3691 
3692  constexpr auto readable_members = filter(type_descriptor::members, [](auto member) { return is_readable(member); });
3693  for_each(readable_members, [&](auto member, [[maybe_unused]] auto index) {
3694  int new_depth = next_depth(depth);
3695 
3696  indent(os, new_depth);
3697  os << get_display_name(member) << " = ";
3698 
3699  if constexpr (util::contains_instance<attr::debug>(member.attributes)) {
3700  // use the debug attribute to print
3701  auto debug_attr = util::get_instance<attr::debug>(member.attributes);
3702  debug_attr.write(os, value);
3703  }
3704  else {
3705  debug_impl(os, member(value), new_depth);
3706  }
3707 
3708  if (!compact || index + 1 != readable_members.size) {
3709  os << ", ";
3710  }
3711  if (!compact) {
3712  indent(os, depth);
3713  os << '\n';
3714  }
3715  });
3716 
3717  if (compact) os << ' ';
3718  indent(os, depth);
3719  os << '}';
3720  }
3721 
3722  template <typename CharT, typename T>
3723  void debug_reflectable(std::basic_ostream<CharT>& os, const T& value, [[maybe_unused]] int depth)
3724  {
3725  using type_descriptor = type_descriptor<T>;
3726  if constexpr (trait::contains_instance_v<attr::debug, typename type_descriptor::attribute_types>) {
3727  // use the debug attribute to print
3728  auto debug_attr = util::get_instance<attr::debug>(type_descriptor::attributes);
3729  debug_attr.write(os, value);
3730  }
3731  else if constexpr (detail::is_ostream_printable_v<CharT, T>) {
3732  // type supports printing natively, just use that
3733  os << value;
3734  }
3735  else {
3736  debug_detailed(os, value, depth);
3737  }
3738  }
3739 
3740  template <typename CharT, typename T>
3741  void debug_container(std::basic_ostream<CharT>& os, const T& value, int depth)
3742  {
3743  bool compact = depth == -1;
3744  os << "[";
3745 
3746  auto end = value.end();
3747  for (auto it = value.begin(); it != end; ++it)
3748  {
3749  if (!compact) os << '\n';
3750  int new_depth = next_depth(depth);
3751  indent(os, new_depth);
3752 
3753  debug_impl(os, *it, new_depth);
3754  if (std::next(it, 1) != end) {
3755  os << ", ";
3756  }
3757  else if (!compact) {
3758  os << '\n';
3759  }
3760  }
3761 
3762  indent(os, depth);
3763  os << "]";
3764  }
3765 
3766  template <typename CharT, typename T>
3767  void debug_impl(std::basic_ostream<CharT>& os, const T& value, [[maybe_unused]] int depth)
3768  {
3769  using no_pointer_t = std::remove_pointer_t<T>;
3770 
3771  if constexpr (std::is_same_v<bool, T>) {
3772  os << (value ? "true" : "false");
3773  }
3774  else if constexpr (std::is_pointer_v<T> && !std::is_void_v<no_pointer_t> && trait::is_reflectable_v<no_pointer_t>) {
3775  if (value == nullptr) {
3776  os << "nullptr";
3777  }
3778  else {
3779  os << '&';
3780  debug_impl(os, *value, -1);
3781  }
3782  }
3783  else if constexpr (trait::is_reflectable_v<T>) {
3784  debug_reflectable(os, value, depth);
3785  }
3786  else if constexpr (detail::is_ostream_printable_v<CharT, T>) {
3787  os << value;
3788  }
3789  else if constexpr (trait::is_container_v<T>) {
3790  debug_container(os, value, depth);
3791  }
3792  else {
3793  os << "(not printable)";
3794  }
3795  }
3796  }
3797 
3798  /**
3799  * Writes the debug representation of value to the given std::ostream.
3800  * Calls the function specified by the debug<F> attribute whenever possible,
3801  * before falling back to recursively interating the members and printing them.
3802  * Takes an optional arguments specifying whether to print a compact representation.
3803  * The compact representation contains no newlines.
3804  */
3805  template <typename CharT, typename T>
3806  void debug(std::basic_ostream<CharT>& os, const T& value, [[maybe_unused]] bool compact)
3807  {
3808  static_assert(trait::is_reflectable_v<T> || trait::is_container_v<T> || detail::is_ostream_printable_v<CharT, T>,
3809  "Type is not reflectable, not a container of reflectable types and does not support operator<<(std::ostream&, T)!");
3810 
3811  detail::debug_impl(os, value, compact ? -1 : 0);
3812  }
3813 
3814  /**
3815  * Writes the compact debug representation of the provided values to the given std::ostream.
3816  */
3817  template <typename CharT, typename... Ts>
3818  void debug_all(std::basic_ostream<CharT>& os, const Ts&... values)
3819  {
3820  refl::runtime::debug(os, std::forward_as_tuple(static_cast<const Ts&>(values)...), true);
3821  }
3822 
3823  /**
3824  * Writes the debug representation of the provided value to an std::string and returns it.
3825  * Takes an optional arguments specifying whether to print a compact representation.
3826  * The compact representation contains no newlines.
3827  */
3828  template <typename CharT = char, typename T>
3829  std::basic_string<CharT> debug_str(const T& value, bool compact = false)
3830  {
3831  std::basic_stringstream<CharT> ss;
3832  debug(ss, value, compact);
3833  return ss.str();
3834  }
3835 
3836  /**
3837  * Writes the compact debug representation of the provided values to an std::string and returns it.
3838  */
3839  template <typename CharT = char, typename... Ts>
3840  std::basic_string<CharT> debug_all_str(const Ts&... values)
3841  {
3842  return refl::runtime::debug_str(std::forward_as_tuple(static_cast<const Ts&>(values)...), true);
3843  }
3844 
3845  /**
3846  * Invokes the specified member with the provided arguments.
3847  * When used with a member that is a field, the function gets or sets the value of the field.
3848  * The list of members is initially filtered by the type of the arguments provided.
3849  * THe filtered list is then searched at runtime by member name for the specified member
3850  * and that member is then invoked by operator(). If no match is found,
3851  * an std::runtime_error is thrown.
3852  */
3853  template <typename U, typename T, typename... Args>
3854  U invoke(T&& target, const char* name, Args&&... args)
3855  {
3856  using type = std::remove_reference_t<T>;
3857  static_assert(refl::trait::is_reflectable_v<type>, "Unsupported type!");
3858  typedef type_descriptor<type> type_descriptor;
3859 
3860  std::optional<U> result;
3861 
3862  bool found{ false };
3863  for_each(type_descriptor::members, [&](auto member) {
3864  using member_t = decltype(member);
3865  if (found) return;
3866 
3867  if constexpr (std::is_invocable_r_v<U, decltype(member), T, Args...>) {
3868  if constexpr (trait::is_member_v<member_t>) {
3869  if (std::strcmp(member.name.c_str(), name) == 0) {
3870  result.emplace(member(target, std::forward<Args>(args)...));
3871  found = true;
3872  }
3873  }
3874  }
3875  });
3876 
3877  if (found) {
3878  return std::move(*result);
3879  }
3880  else {
3881  throw std::runtime_error(std::string("The member ")
3882  + type_descriptor::name.str() + "::" + name
3883  + " is not compatible with the provided parameters or return type, is not reflected or does not exist!");
3884  }
3885  }
3886 
3887  } // namespace runtime
3888 
3889 } // namespace refl
3890 
3891 namespace refl::detail
3892 {
3893  constexpr bool validate_attr_unique(type_list<>) noexcept
3894  {
3895  return true;
3896  }
3897 
3898  /** Statically asserts that all types in Ts... are unique. */
3899  template <typename T, typename... Ts>
3900  constexpr bool validate_attr_unique(type_list<T, Ts...>) noexcept
3901  {
3902  constexpr bool cond = (... && (!std::is_same_v<T, Ts> && validate_attr_unique(type_list<Ts>{})));
3903  static_assert(cond, "Some of the attributes provided have duplicate types!");
3904  return cond;
3905  }
3906 
3907  template <typename Req, typename Attr>
3908  constexpr bool validate_attr_usage() noexcept
3909  {
3910  return std::is_base_of_v<Req, Attr>;
3911  }
3912 
3913  /**
3914  * Statically asserts that all arguments inherit
3915  * from the appropriate bases to be used with Req.
3916  * Req must be one of the types defined in attr::usage.
3917  */
3918  template <typename Req, typename... Args>
3919  constexpr auto make_attributes(Args&&... args) noexcept
3920  {
3921  constexpr bool check_unique = validate_attr_unique(type_list<Args...>{});
3922  static_assert(check_unique, "Some of the supplied attributes cannot be used on this declaration!");
3923 
3924  constexpr bool check_usage = (... && validate_attr_usage<Req, trait::remove_qualifiers_t<Args>>());
3925  static_assert(check_usage, "Some of the supplied attributes cannot be used on this declaration!");
3926 
3927  return std::make_tuple(std::forward<Args>(args)...);
3928  }
3929 
3930  template <typename T, typename...>
3931  struct head
3932  {
3933  typedef T type;
3934  };
3935 
3936  /**
3937  * Accesses the first type T of Ts...
3938  * Used to allow for SFIANE to kick in in the implementation of REFL_FUNC.
3939  */
3940  template <typename T, typename... Ts>
3941  using head_t = typename head<T, Ts...>::type;
3942 
3943  template <typename T, typename U>
3944  struct transfer_const
3945  {
3946  using type = std::conditional_t<std::is_const_v<T>, std::add_const_t<U>, U>;
3947  };
3948 
3949  template <typename T, typename U>
3950  struct transfer_volatile
3951  {
3952  using type = std::conditional_t<std::is_volatile_v<T>, std::add_volatile_t<U>, U>;
3953  };
3954 
3955  template <typename T, typename U>
3956  struct transfer_cv : transfer_const<T, typename transfer_volatile<T, U>::type>
3957  {
3958  };
3959 
3960  template <typename T, typename U>
3961  struct transfer_lvalue_ref
3962  {
3963  using type = std::conditional_t<std::is_lvalue_reference_v<T>, std::add_lvalue_reference_t<U>, U>;
3964  };
3965 
3966  template <typename T, typename U>
3967  struct transfer_rvalue_ref
3968  {
3969  using type = std::conditional_t<std::is_rvalue_reference_v<T>, std::add_rvalue_reference_t<U>, U>;
3970  };
3971 
3972  template <typename T, typename U>
3973  struct transfer_ref : transfer_rvalue_ref<T, typename transfer_lvalue_ref<T, U>::type>
3974  {
3975  };
3976 
3977  template <typename T, typename U>
3978  struct transfer_cvref : transfer_ref<T, typename transfer_cv<std::remove_reference_t<T>, U>::type>
3979  {
3980  };
3981 
3982  template <typename T, typename U>
3983  constexpr auto forward_cast(std::remove_reference_t<T>& t) -> decltype(static_cast<typename transfer_cvref<T, U>::type&&>(t))
3984  {
3985  return static_cast<typename transfer_cvref<T, U>::type&&>(t);
3986  }
3987 
3988  template <typename T, typename U>
3989  constexpr auto forward_cast(std::remove_reference_t<T>&& t) -> decltype(static_cast<typename transfer_cvref<T, U>::type&&>(t))
3990  {
3991  static_assert(!std::is_lvalue_reference_v<T>, "template argument substituting T is an lvalue reference type");
3992  return static_cast<typename transfer_cvref<T, U>::type&&>(t);
3993  }
3994 
3995  template <typename T>
3996  constexpr auto get_type_name()
3997  {
3998  if constexpr (trait::is_reflectable_v<T>) {
3999  return type_descriptor<T>::name;
4000  }
4001  else {
4002  return make_const_string("(unknown)");
4003  }
4004  }
4005 
4006 } // namespace refl::detail
4007 
4008 /********************************/
4009 /* Metadata-generation macros */
4010 /********************************/
4011 
4012 #define REFL_DETAIL_STR_IMPL(...) #__VA_ARGS__
4013 /** Used to stringify input separated by commas (e.g. template specializations with multiple types). */
4014 #define REFL_DETAIL_STR(...) REFL_DETAIL_STR_IMPL(__VA_ARGS__)
4015 /** Used to group input containing commas (e.g. template specializations with multiple types). */
4016 #define REFL_DETAIL_GROUP(...) __VA_ARGS__
4017 
4018 /**
4019  * Expands to the appropriate attributes static member variable.
4020  * DeclType must be the name of one of the constraints defined in attr::usage.
4021  * __VA_ARGS__ is the list of attributes.
4022  */
4023 #define REFL_DETAIL_ATTRIBUTES(DeclType, ...)
4024  static constexpr auto attributes{ ::refl::detail::make_attributes<::refl::attr::usage:: DeclType>(__VA_ARGS__) };
4025 
4026 /**
4027  * Expands to the body of a type_info__ specialization.
4028  */
4029 #define REFL_DETAIL_TYPE_BODY(TypeName, ...)
4030  typedef REFL_DETAIL_GROUP TypeName type;
4031  REFL_DETAIL_ATTRIBUTES(type, __VA_ARGS__)
4032  static constexpr auto name{ ::refl::util::make_const_string(REFL_DETAIL_STR(REFL_DETAIL_GROUP TypeName)) };
4033  static constexpr size_t member_index_offset = __COUNTER__ + 1;
4034  template <size_t, typename = void>
4035  struct member {};
4036 
4037 /**
4038  * Creates reflection information for a specified type. Takes an optional attribute list.
4039  * This macro must only be expanded in the global namespace.
4040  *
4041  * # Examples:
4042  * ```
4043  * REFL_TYPE(Point)
4044  * ...
4045  * REFL_END
4046  * ```
4047  */
4048 #define REFL_TYPE(TypeName, ...)
4049  namespace refl_impl::metadata { template<> struct type_info__<TypeName> {
4050  REFL_DETAIL_TYPE_BODY((TypeName), __VA_ARGS__)
4051 
4052 /**
4053  * Creates reflection information for a specified type template. Takes an optional attribute list.
4054  * TemplateDeclaration must be a panenthesis-enclosed list declaring the template parameters. (e.g. (typename A, typename B)).
4055  * TypeName must be the fully-specialized type name and should also be enclosed in panenthesis. (e.g. (MyType<A, B>))
4056  * This macro must only be expanded in the global namespace.
4057  *
4058  * # Examples:
4059  * ```
4060  * REFL_TEMPLATE((typename T), (std::vector<T>))
4061  * ...
4062  * REFL_END
4063  * ```
4064  */
4065 #define REFL_TEMPLATE(TemplateDeclaration, TypeName, ...)
4066  namespace refl_impl::metadata { template <REFL_DETAIL_GROUP TemplateDeclaration> struct type_info__<REFL_DETAIL_GROUP TypeName> {
4067  REFL_DETAIL_TYPE_BODY(TypeName, __VA_ARGS__)
4068 
4069 /**
4070  * Terminated the declaration of reflection metadata for a particular type.
4071  *
4072  * # Examples:
4073  * ```
4074  * REFL_TYPE(Point)
4075  * ...
4076  * REFL_END
4077  */
4078 #define REFL_END
4079  static constexpr size_t member_count{ __COUNTER__ - member_index_offset };
4080  }; }
4081 
4082 #define REFL_DETAIL_MEMBER_HEADER template<typename Unused__> struct member<__COUNTER__ - member_index_offset, Unused__>
4083 
4084 #define REFL_DETAIL_MEMBER_COMMON(MemberType_, MemberName_, ...)
4085  typedef ::refl::member::MemberType_ member_type;
4086  static constexpr auto name{ ::refl::util::make_const_string(REFL_DETAIL_STR(MemberName_)) };
4087  REFL_DETAIL_ATTRIBUTES(MemberType_, __VA_ARGS__)
4088 
4089 /** Creates the support infrastructure needed for the refl::runtime::proxy type. */
4090 /*
4091  There can be a total of 12 differently qualified member functions with the same name.
4092  Providing remaps for non-const and const-only strikes a balance between compilation time and usability.
4093  And even though there are many other remap implementation possibilities (like virtual, field variants),
4094  adding them was considered to not be efficient from a compilation-time point of view.
4095 */
4096 #define REFL_DETAIL_MEMBER_PROXY(MemberName_)
4097  template <typename Proxy> struct remap {
4098  template <typename... Args> decltype(auto) MemberName_(Args&&... args) {
4099  return Proxy::invoke_impl(static_cast<Proxy&>(*this), ::std::forward<Args>(args)...);
4100  }
4101  template <typename... Args> decltype(auto) MemberName_(Args&&... args) const {
4102  return Proxy::invoke_impl(static_cast<const Proxy&>(*this), ::std::forward<Args>(args)...);
4103  }
4104  }
4105 
4106 /**
4107  * Creates reflection information for a public field. Takes an optional attribute list.
4108  */
4109 #define REFL_FIELD(FieldName_, ...)
4110  REFL_DETAIL_MEMBER_HEADER {
4111  REFL_DETAIL_MEMBER_COMMON(field, FieldName_, __VA_ARGS__)
4112  public:
4113  typedef decltype(type::FieldName_) value_type;
4114  static constexpr auto pointer{ &type::FieldName_ };
4115  REFL_DETAIL_MEMBER_PROXY(FieldName_);
4116  };
4117 
4118 /**
4119  * Creates reflection information for a public functions. Takes an optional attribute list.
4120  */
4121 #define REFL_FUNC(FunctionName_, ...)
4122  REFL_DETAIL_MEMBER_HEADER {
4123  REFL_DETAIL_MEMBER_COMMON(function, FunctionName_, __VA_ARGS__)
4124  public:
4125  template<typename Self, typename... Args> static constexpr auto invoke(Self&& self, Args&&... args) -> decltype(::refl::detail::forward_cast<Self, type>(self).FunctionName_(::std::forward<Args>(args)...)) {
4126  return ::refl::detail::forward_cast<Self, type>(self).FunctionName_(::std::forward<Args>(args)...);
4127  }
4128  template<typename... Args> static constexpr auto invoke(Args&&... args) -> decltype(::refl::detail::head_t<type, Args...>::FunctionName_(::std::declval<Args>()...)) {
4129  return ::refl::detail::head_t<type, Args...>::FunctionName_(::std::forward<Args>(args)...);
4130  }
4131  template <typename Dummy = void>
4132  static constexpr auto pointer() -> decltype(&::refl::detail::head_t<type, Dummy>::FunctionName_) { return &::refl::detail::head_t<type, Dummy>::FunctionName_; }
4133  template <typename Pointer>
4134  static constexpr auto resolve() -> ::std::decay_t<decltype(Pointer(&type::FunctionName_))> { return Pointer(&type::FunctionName_); }
4135  REFL_DETAIL_MEMBER_PROXY(FunctionName_);
4136  };
4137 
4138 /********************************/
4139 /* Default Reflection Metadata */
4140 /********************************/
4141 
4142 #define REFL_DETAIL_PRIMITIVE(TypeName)
4143  REFL_TYPE(TypeName)
4144  REFL_END
4145 
4146  // Char types.
4147  REFL_DETAIL_PRIMITIVE(char);
4148  REFL_DETAIL_PRIMITIVE(wchar_t);
4149  REFL_DETAIL_PRIMITIVE(char16_t);
4150  REFL_DETAIL_PRIMITIVE(char32_t);
4151 #ifdef __cpp_lib_char8_t
4152  REFL_DETAIL_PRIMITIVE(char8_t);
4153 #endif
4154 
4155  // Integral types.
4156  REFL_DETAIL_PRIMITIVE(bool);
4157  REFL_DETAIL_PRIMITIVE(signed char);
4158  REFL_DETAIL_PRIMITIVE(unsigned char);
4159  REFL_DETAIL_PRIMITIVE(signed short);
4160  REFL_DETAIL_PRIMITIVE(unsigned short);
4161  REFL_DETAIL_PRIMITIVE(signed int);
4162  REFL_DETAIL_PRIMITIVE(unsigned int);
4163  REFL_DETAIL_PRIMITIVE(signed long);
4164  REFL_DETAIL_PRIMITIVE(unsigned long);
4165  REFL_DETAIL_PRIMITIVE(signed long long);
4166  REFL_DETAIL_PRIMITIVE(unsigned long long);
4167 
4168  // Floating point types.
4169  REFL_DETAIL_PRIMITIVE(float);
4170  REFL_DETAIL_PRIMITIVE(double);
4171  REFL_DETAIL_PRIMITIVE(long double);
4172 
4173  // Other types.
4174  REFL_DETAIL_PRIMITIVE(decltype(nullptr));
4175 
4176  // Void type.
4177  REFL_TYPE(void)
4178  REFL_END
4179 
4180 #undef REFL_DETAIL_PRIMITIVE
4181 
4182 #define REFL_DETAIL_POINTER(Ptr)
4183  template<typename T>
4184  struct type_info__<T Ptr> {
4185  typedef T Ptr type;
4186  template <size_t N>
4187  struct member {};
4188  static constexpr auto name{ ::refl::detail::get_type_name<T>() + ::refl::util::make_const_string(#Ptr) };
4189  static constexpr ::std::tuple<> attributes{ };
4190  static constexpr size_t member_count{ 0 };
4191  }
4192 
4193  namespace refl_impl
4194  {
4195  namespace metadata
4196  {
4197  REFL_DETAIL_POINTER(*);
4198  REFL_DETAIL_POINTER(&);
4199  REFL_DETAIL_POINTER(&&);
4200  }
4201  }
4202 
4203 #undef REFL_DETAIL_POINTER
4204 
4205 namespace refl::detail
4206 {
4207  template <typename CharT>
4208  std::basic_string<CharT> convert(const std::string& str)
4209  {
4210  return std::basic_string<CharT>(str.begin(), str.end());
4211  }
4212 
4213 #ifdef __cpp_lib_string_view
4214  struct write_basic_string_view
4215  {
4216  template <typename CharT, typename Traits>
4217  void operator()(std::basic_ostream<CharT>& os, std::basic_string_view<CharT, Traits> str) const
4218  {
4219  // some vers of clang dont have std::quoted(string_view) overload
4220  if (!str.back()) { // no copy needed when null-terminated
4221  os << std::quoted(str.data());
4222  }
4223  else {
4224  os << std::quoted(std::basic_string<CharT, Traits>(str.begin(), str.end()));
4225  }
4226  }
4227  };
4228 #endif
4229 
4230  struct write_basic_string
4231  {
4232  template <typename CharT, typename Traits, typename Allocator>
4233  void operator()(std::basic_ostream<CharT>& os, const std::basic_string<CharT, Traits, Allocator>& str) const
4234  {
4235  os << std::quoted(str);
4236  }
4237  };
4238 
4239  struct write_exception
4240  {
4241  template <typename CharT>
4242  void operator()(std::basic_ostream<CharT>& os, const std::exception& e) const
4243  {
4244  os << convert<CharT>("Exception");
4245  #ifdef REFL_RTTI_ENABLED
4246  os << convert<CharT>(" (") << convert<CharT>(typeid(e).name()) << convert<CharT>(")");
4247  #endif
4248  os << convert<CharT>(": `") << e.what() << convert<CharT>("`");
4249  }
4250  };
4251 
4252  struct write_tuple
4253  {
4254  template <typename CharT, typename Tuple, size_t... Idx>
4255  void write(std::basic_ostream<CharT>& os, Tuple&& t, std::index_sequence<Idx...>) const
4256  {
4257  os << CharT('(');
4258  for_each(type_list<std::integral_constant<size_t, Idx>...>{}, [&](auto idx_c) {
4259  using idx_t = decltype(idx_c);
4260  runtime::debug(os, std::get<idx_t::value>(t));
4261  if constexpr (sizeof...(Idx) - 1 != idx_t::value) {
4262  os << convert<CharT>(", ");
4263  }
4264  });
4265  os << CharT(')');
4266  }
4267 
4268  template <typename CharT, typename... Ts>
4269  void operator()(std::basic_ostream<CharT>& os, const std::tuple<Ts...>& t) const
4270  {
4271  write(os, t, std::make_index_sequence<sizeof...(Ts)>{});
4272  }
4273  };
4274 
4275  struct write_pair
4276  {
4277  template <typename CharT, typename K, typename V>
4278  void operator()(std::basic_ostream<CharT>& os, const std::pair<K, V>& t) const
4279  {
4280  os << CharT('(');
4281  runtime::debug(os, t.first);
4282  os << convert<CharT>(", ");
4283  runtime::debug(os, t.second);
4284  os << CharT(')');
4285  }
4286  };
4287 
4288  struct write_unique_ptr
4289  {
4290  template <typename CharT, typename T, typename D>
4291  void operator()(std::basic_ostream<CharT>& os, const std::unique_ptr<T, D>& t) const
4292  {
4293  runtime::debug(os, t.get(), true);
4294  }
4295  };
4296 
4297  struct write_shared_ptr
4298  {
4299  template <typename CharT, typename T>
4300  void operator()(std::basic_ostream<CharT>& os, const std::shared_ptr<T>& t) const
4301  {
4302  runtime::debug(os, t.get(), true);
4303  }
4304  };
4305 
4306  struct write_weak_ptr
4307  {
4308  template <typename CharT, typename T>
4309  void operator()(std::basic_ostream<CharT>& os, const std::weak_ptr<T>& t) const
4310  {
4311  runtime::debug(os, t.lock().get(), true);
4312  }
4313  };
4314 
4315  struct write_complex
4316  {
4317  template <typename CharT, typename T>
4318  void operator()(std::basic_ostream<CharT>& os, const std::complex<T>& t) const
4319  {
4320  runtime::debug(os, t.real());
4321  os << CharT('+');
4322  runtime::debug(os, t.imag());
4323  os << CharT('i');
4324  }
4325  };
4326 } // namespace refl::detail
4327 
4328 // Custom reflection information for
4329 // some common built-in types (std::basic_string, std::tuple, std::pair).
4330 
4331 #ifndef REFL_NO_STD_SUPPORT
4332 
4333 REFL_TYPE(std::exception, debug{ refl::detail::write_exception() })
4334  REFL_FUNC(what, property{ })
4335 REFL_END
4336 
4338  (typename Elem, typename Traits, typename Alloc),
4340  debug{ refl::detail::write_basic_string() })
4341  REFL_FUNC(size, property{ })
4342  REFL_FUNC(data, property{ })
4343 REFL_END
4344 
4345 #ifdef __cpp_lib_string_view
4346 
4348  (typename Elem, typename Traits),
4350  debug{ refl::detail::write_basic_string_view() })
4351  REFL_FUNC(size, property{ })
4352  REFL_FUNC(data, property{ })
4353 REFL_END
4354 
4355 #endif
4356 
4358  (typename... Ts),
4360  debug{ refl::detail::write_tuple() })
4361 REFL_END
4362 
4364  (typename T, typename D),
4366  debug{ refl::detail::write_unique_ptr() })
4367 REFL_END
4368 
4370  (typename T),
4372  debug{ refl::detail::write_shared_ptr() })
4373 REFL_END
4374 
4376  (typename K, typename V),
4377  (std::pair<K, V>),
4378  debug{ refl::detail::write_pair() })
4379 REFL_END
4380 
4381 #ifndef REFL_NO_STD_COMPLEX
4382 
4384  (typename T),
4386  debug{ refl::detail::write_complex() })
4387 REFL_END
4388 
4389 #endif // !REFL_NO_STD_COMPLEX
4390 
4391 #endif // !REFL_NO_STD_SUPPORT
4392 
4393 #ifndef REFL_NO_AUTO_MACRO
4394 
4395 #define REFL_DETAIL_EXPAND(x) x
4396 #define REFL_DETAIL_FOR_EACH_0(...)
4397 #define REFL_DETAIL_FOR_EACH_1(what, x, ...) what(x)
4398 #define REFL_DETAIL_FOR_EACH_2(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_1(what, __VA_ARGS__))
4399 #define REFL_DETAIL_FOR_EACH_3(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_2(what, __VA_ARGS__))
4400 #define REFL_DETAIL_FOR_EACH_4(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_3(what, __VA_ARGS__))
4401 #define REFL_DETAIL_FOR_EACH_5(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_4(what, __VA_ARGS__))
4402 #define REFL_DETAIL_FOR_EACH_6(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_5(what, __VA_ARGS__))
4403 #define REFL_DETAIL_FOR_EACH_7(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_6(what, __VA_ARGS__))
4404 #define REFL_DETAIL_FOR_EACH_8(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_7(what, __VA_ARGS__))
4405 #define REFL_DETAIL_FOR_EACH_9(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_8(what, __VA_ARGS__))
4406 #define REFL_DETAIL_FOR_EACH_10(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_9(what, __VA_ARGS__))
4407 #define REFL_DETAIL_FOR_EACH_11(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_10(what, __VA_ARGS__))
4408 #define REFL_DETAIL_FOR_EACH_12(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_11(what, __VA_ARGS__))
4409 #define REFL_DETAIL_FOR_EACH_13(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_12(what, __VA_ARGS__))
4410 #define REFL_DETAIL_FOR_EACH_14(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_13(what, __VA_ARGS__))
4411 #define REFL_DETAIL_FOR_EACH_15(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_14(what, __VA_ARGS__))
4412 #define REFL_DETAIL_FOR_EACH_16(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_15(what, __VA_ARGS__))
4413 #define REFL_DETAIL_FOR_EACH_17(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_16(what, __VA_ARGS__))
4414 #define REFL_DETAIL_FOR_EACH_18(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_17(what, __VA_ARGS__))
4415 #define REFL_DETAIL_FOR_EACH_19(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_18(what, __VA_ARGS__))
4416 #define REFL_DETAIL_FOR_EACH_20(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_19(what, __VA_ARGS__))
4417 #define REFL_DETAIL_FOR_EACH_21(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_20(what, __VA_ARGS__))
4418 #define REFL_DETAIL_FOR_EACH_22(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_21(what, __VA_ARGS__))
4419 #define REFL_DETAIL_FOR_EACH_23(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_22(what, __VA_ARGS__))
4420 #define REFL_DETAIL_FOR_EACH_24(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_23(what, __VA_ARGS__))
4421 #define REFL_DETAIL_FOR_EACH_25(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_24(what, __VA_ARGS__))
4422 #define REFL_DETAIL_FOR_EACH_26(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_25(what, __VA_ARGS__))
4423 #define REFL_DETAIL_FOR_EACH_27(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_26(what, __VA_ARGS__))
4424 #define REFL_DETAIL_FOR_EACH_28(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_27(what, __VA_ARGS__))
4425 #define REFL_DETAIL_FOR_EACH_29(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_28(what, __VA_ARGS__))
4426 #define REFL_DETAIL_FOR_EACH_30(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_29(what, __VA_ARGS__))
4427 #define REFL_DETAIL_FOR_EACH_31(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_30(what, __VA_ARGS__))
4428 #define REFL_DETAIL_FOR_EACH_32(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_31(what, __VA_ARGS__))
4429 #define REFL_DETAIL_FOR_EACH_33(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_32(what, __VA_ARGS__))
4430 #define REFL_DETAIL_FOR_EACH_34(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_33(what, __VA_ARGS__))
4431 #define REFL_DETAIL_FOR_EACH_35(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_34(what, __VA_ARGS__))
4432 #define REFL_DETAIL_FOR_EACH_36(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_35(what, __VA_ARGS__))
4433 #define REFL_DETAIL_FOR_EACH_37(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_36(what, __VA_ARGS__))
4434 #define REFL_DETAIL_FOR_EACH_38(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_37(what, __VA_ARGS__))
4435 #define REFL_DETAIL_FOR_EACH_39(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_38(what, __VA_ARGS__))
4436 #define REFL_DETAIL_FOR_EACH_40(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_39(what, __VA_ARGS__))
4437 #define REFL_DETAIL_FOR_EACH_41(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_40(what, __VA_ARGS__))
4438 #define REFL_DETAIL_FOR_EACH_42(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_41(what, __VA_ARGS__))
4439 #define REFL_DETAIL_FOR_EACH_43(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_42(what, __VA_ARGS__))
4440 #define REFL_DETAIL_FOR_EACH_44(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_43(what, __VA_ARGS__))
4441 #define REFL_DETAIL_FOR_EACH_45(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_44(what, __VA_ARGS__))
4442 #define REFL_DETAIL_FOR_EACH_46(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_45(what, __VA_ARGS__))
4443 #define REFL_DETAIL_FOR_EACH_47(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_46(what, __VA_ARGS__))
4444 #define REFL_DETAIL_FOR_EACH_48(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_47(what, __VA_ARGS__))
4445 #define REFL_DETAIL_FOR_EACH_49(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_48(what, __VA_ARGS__))
4446 #define REFL_DETAIL_FOR_EACH_50(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_49(what, __VA_ARGS__))
4447 #define REFL_DETAIL_FOR_EACH_51(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_50(what, __VA_ARGS__))
4448 #define REFL_DETAIL_FOR_EACH_52(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_51(what, __VA_ARGS__))
4449 #define REFL_DETAIL_FOR_EACH_53(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_52(what, __VA_ARGS__))
4450 #define REFL_DETAIL_FOR_EACH_54(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_53(what, __VA_ARGS__))
4451 #define REFL_DETAIL_FOR_EACH_55(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_54(what, __VA_ARGS__))
4452 #define REFL_DETAIL_FOR_EACH_56(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_55(what, __VA_ARGS__))
4453 #define REFL_DETAIL_FOR_EACH_57(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_56(what, __VA_ARGS__))
4454 #define REFL_DETAIL_FOR_EACH_58(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_57(what, __VA_ARGS__))
4455 #define REFL_DETAIL_FOR_EACH_59(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_58(what, __VA_ARGS__))
4456 #define REFL_DETAIL_FOR_EACH_60(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_59(what, __VA_ARGS__))
4457 #define REFL_DETAIL_FOR_EACH_61(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_60(what, __VA_ARGS__))
4458 #define REFL_DETAIL_FOR_EACH_62(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_61(what, __VA_ARGS__))
4459 #define REFL_DETAIL_FOR_EACH_63(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_62(what, __VA_ARGS__))
4460 #define REFL_DETAIL_FOR_EACH_64(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_63(what, __VA_ARGS__))
4461 #define REFL_DETAIL_FOR_EACH_65(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_64(what, __VA_ARGS__))
4462 #define REFL_DETAIL_FOR_EACH_66(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_65(what, __VA_ARGS__))
4463 #define REFL_DETAIL_FOR_EACH_67(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_66(what, __VA_ARGS__))
4464 #define REFL_DETAIL_FOR_EACH_68(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_67(what, __VA_ARGS__))
4465 #define REFL_DETAIL_FOR_EACH_69(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_68(what, __VA_ARGS__))
4466 #define REFL_DETAIL_FOR_EACH_70(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_69(what, __VA_ARGS__))
4467 #define REFL_DETAIL_FOR_EACH_71(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_70(what, __VA_ARGS__))
4468 #define REFL_DETAIL_FOR_EACH_72(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_71(what, __VA_ARGS__))
4469 #define REFL_DETAIL_FOR_EACH_73(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_72(what, __VA_ARGS__))
4470 #define REFL_DETAIL_FOR_EACH_74(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_73(what, __VA_ARGS__))
4471 #define REFL_DETAIL_FOR_EACH_75(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_74(what, __VA_ARGS__))
4472 #define REFL_DETAIL_FOR_EACH_76(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_75(what, __VA_ARGS__))
4473 #define REFL_DETAIL_FOR_EACH_77(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_76(what, __VA_ARGS__))
4474 #define REFL_DETAIL_FOR_EACH_78(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_77(what, __VA_ARGS__))
4475 #define REFL_DETAIL_FOR_EACH_79(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_78(what, __VA_ARGS__))
4476 #define REFL_DETAIL_FOR_EACH_80(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_79(what, __VA_ARGS__))
4477 #define REFL_DETAIL_FOR_EACH_81(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_80(what, __VA_ARGS__))
4478 #define REFL_DETAIL_FOR_EACH_82(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_81(what, __VA_ARGS__))
4479 #define REFL_DETAIL_FOR_EACH_83(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_82(what, __VA_ARGS__))
4480 #define REFL_DETAIL_FOR_EACH_84(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_83(what, __VA_ARGS__))
4481 #define REFL_DETAIL_FOR_EACH_85(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_84(what, __VA_ARGS__))
4482 #define REFL_DETAIL_FOR_EACH_86(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_85(what, __VA_ARGS__))
4483 #define REFL_DETAIL_FOR_EACH_87(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_86(what, __VA_ARGS__))
4484 #define REFL_DETAIL_FOR_EACH_88(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_87(what, __VA_ARGS__))
4485 #define REFL_DETAIL_FOR_EACH_89(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_88(what, __VA_ARGS__))
4486 #define REFL_DETAIL_FOR_EACH_90(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_89(what, __VA_ARGS__))
4487 #define REFL_DETAIL_FOR_EACH_91(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_90(what, __VA_ARGS__))
4488 #define REFL_DETAIL_FOR_EACH_92(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_91(what, __VA_ARGS__))
4489 #define REFL_DETAIL_FOR_EACH_93(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_92(what, __VA_ARGS__))
4490 #define REFL_DETAIL_FOR_EACH_94(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_93(what, __VA_ARGS__))
4491 #define REFL_DETAIL_FOR_EACH_95(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_94(what, __VA_ARGS__))
4492 #define REFL_DETAIL_FOR_EACH_96(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_95(what, __VA_ARGS__))
4493 #define REFL_DETAIL_FOR_EACH_97(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_96(what, __VA_ARGS__))
4494 #define REFL_DETAIL_FOR_EACH_98(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_97(what, __VA_ARGS__))
4495 #define REFL_DETAIL_FOR_EACH_99(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_98(what, __VA_ARGS__))
4496 #define REFL_DETAIL_FOR_EACH_100(what, x, ...) what(x) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_99(what, __VA_ARGS__))
4497 
4498 #define REFL_DETAIL_FOR_EACH_NARG(...) REFL_DETAIL_FOR_EACH_NARG_(__VA_ARGS__, REFL_DETAIL_FOR_EACH_RSEQ_N())
4499 #define REFL_DETAIL_FOR_EACH_NARG_(...) REFL_DETAIL_EXPAND(REFL_DETAIL_FOR_EACH_ARG_N(__VA_ARGS__))
4500 #define REFL_DETAIL_FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, N, ...) N
4501 #define REFL_DETAIL_FOR_EACH_RSEQ_N() 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
4502 #define REFL_DETAIL_CONCATENATE(x, y) x##y
4503 #define REFL_DETAIL_FOR_EACH_(N, what, ...) REFL_DETAIL_EXPAND(REFL_DETAIL_CONCATENATE(REFL_DETAIL_FOR_EACH_, N)(what, __VA_ARGS__))
4504 #define REFL_DETAIL_FOR_EACH(what, ...) REFL_DETAIL_FOR_EACH_(REFL_DETAIL_FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
4505 
4506 // Intellisense does not work nicely with passing variadic parameters (for the attributes)
4507 // through all of the macro expansions and causes differently named member declarations to be
4508 // used during code inspection.
4509 #ifdef __INTELLISENSE__
4510 
4511 #define REFL_DETAIL_EX_1_type(X, ...) REFL_TYPE(X)
4512 #define REFL_DETAIL_EX_1_template(X, Y, ...) REFL_TEMPLATE(X, Y)
4513 #define REFL_DETAIL_EX_1_field(X, ...) REFL_FIELD(X)
4514 #define REFL_DETAIL_EX_1_func(X, ...) REFL_FUNC(X)
4515 
4516 #else // !defined(__INTELLISENSE__)
4517 
4518 #define REFL_DETAIL_EX_1_type(...) REFL_DETAIL_EX_EXPAND(REFL_DETAIL_EX_DEFER(REFL_TYPE)(__VA_ARGS__))
4519 #define REFL_DETAIL_EX_1_template(...) REFL_DETAIL_EX_EXPAND(REFL_DETAIL_EX_DEFER(REFL_TEMPLATE)(__VA_ARGS__))
4520 #define REFL_DETAIL_EX_1_field(...) REFL_DETAIL_EX_EXPAND(REFL_DETAIL_EX_DEFER(REFL_FIELD)(__VA_ARGS__))
4521 #define REFL_DETAIL_EX_1_func(...) REFL_DETAIL_EX_EXPAND(REFL_DETAIL_EX_DEFER(REFL_FUNC)(__VA_ARGS__))
4522 
4523 #endif // __INTELLISENSE__
4524 
4525 #define REFL_DETAIL_EX_(Specifier, ...) REFL_DETAIL_EX_1_##Specifier __VA_ARGS__
4526 
4527 #define REFL_DETAIL_EX_EMPTY()
4528 #define REFL_DETAIL_EX_DEFER(Id) Id REFL_DETAIL_EX_EMPTY()
4529 #define REFL_DETAIL_EX_EXPAND(...) __VA_ARGS__
4530 
4531 #define REFL_DETAIL_EX_END() REFL_END
4532 
4533 #define REFL_AUTO(...) REFL_DETAIL_FOR_EACH(REFL_DETAIL_EX_, __VA_ARGS__) REFL_DETAIL_EX_EXPAND(REFL_DETAIL_EX_DEFER(REFL_DETAIL_EX_END)())
4534 
4535 #endif // !defined(REFL_NO_AUTO_MACRO)
4536 
4537 #endif // REFL_INCLUDE_HPP
refl::reflect
constexpr type_descriptor< T > reflect(const T &) noexcept
Returns the type descriptor for the non-qualified type T.
Definition: refl.hpp:3442
refl::attr::debug::write
const F write
Definition: refl.hpp:1950
refl::descriptor::type_descriptor::declared_members
static constexpr declared_member_types declared_members
The list of declared member descriptors.
Definition: refl.hpp:2549
refl::descriptor::field_descriptor::operator()
constexpr auto operator()(Args &&... args) const noexcept -> decltype(invoker::invoke(std::forward< Args >(args)...))
A synonym for get().
Definition: refl.hpp:2395
refl::descriptor::type_descriptor::bases
static constexpr base_types bases
The declared and inherited base types of T.
Definition: refl.hpp:2543
refl::descriptor::type_descriptor::declared_member_types
declared_member_list< T > declared_member_types
A synonym for declared_member_list<T>.
Definition: refl.hpp:2519
refl::util::const_string::find
constexpr auto find(char ch, size_t pos=0) const noexcept
Searches the string for the first occurrence of the character and returns its position.
Definition: refl.hpp:216
refl::util::get
constexpr const auto & get(const std::tuple< Ts... > &ts) noexcept
A synonym for std::get<N>(tuple).
Definition: refl.hpp:1803
refl::descriptor::field_descriptor::get
static constexpr decltype(auto) get() noexcept
Returns the value of the field.
Definition: refl.hpp:2375
refl::descriptor::get_debug_name
const char * get_debug_name(MemberDescriptor d)
Returns the debug name of T.
Definition: refl.hpp:3198
refl::trait::remove_qualifiers::type
std::remove_cv_t< std::remove_reference_t< T > > type
Definition: refl.hpp:625
refl::trait::is_property
Checks whether T is marked as a property.
Definition: refl.hpp:2091
refl::descriptor::is_readable
constexpr bool is_readable(MemberDescriptor) noexcept
Checks if T is a 0-arg const-qualified member function with a property attribute or a field.
Definition: refl.hpp:3060
refl::util::count_if
constexpr size_t count_if(type_list< Ts... > list, F &&f)
Counts the number of times the predicate F returns true.
Definition: refl.hpp:1666
refl::runtime::proxy::target_type
Target target_type
Definition: refl.hpp:3597
refl::util::get
constexpr const T & get(const std::tuple< Ts... > &ts) noexcept
A synonym for std::get<T>(tuple).
Definition: refl.hpp:1817
refl::util::apply
constexpr auto apply(type_list< Ts... >, F &&f)
Applies a function to the elements of the type_list.
Definition: refl.hpp:1789
refl::util::const_string::size
static constexpr size_t size
The length of the string excluding the terminating '\0' character.
Definition: refl.hpp:123
refl::util::operator+
constexpr const_string< N+M - 1 > operator+(const char(&a)[N], const const_string< M > &b) noexcept
Concatenates a C-style string with a const_string.
Definition: refl.hpp:331
refl::util::as_tuple
constexpr std::tuple< Ts... > as_tuple(type_list< Ts... >) noexcept
Creates a matching std::tuple from a type_list.
Definition: refl.hpp:1524
refl::util::contains
constexpr bool contains(type_list< Ts... >)
Returns true if the type_list contains the specified type.
Definition: refl.hpp:1753
refl::trait::is_instance_of
Detects whther the type U is a template specialization of T.
Definition: refl.hpp:1218
refl::descriptor::invoke
constexpr auto invoke(MemberDescriptor d, Args &&... args) noexcept -> decltype(d(std::forward< Args >(args)...))
Invokes the member with the specified arguments.
Definition: refl.hpp:2776
refl::is_reflectable
constexpr bool is_reflectable() noexcept
Returns true if the type T is reflectable.
Definition: refl.hpp:3421
refl::descriptor::resolve
constexpr auto resolve(FunctionDescriptor d) noexcept
Resolves the function pointer as a pointer of the specified type.
Definition: refl.hpp:2886
refl::descriptor::function_descriptor::operator()
constexpr auto operator()(Args &&... args) const -> decltype(invoke(std::declval< Args >()...))
A synonym for invoke(args...).
Definition: refl.hpp:2437
refl::descriptor::get_attributes
constexpr const auto & get_attributes(Descriptor d) noexcept
Returns a const reference to the descriptor's attribute tuple.
Definition: refl.hpp:2604
REFL_TEMPLATE
#define REFL_TEMPLATE(TemplateDeclaration, TypeName,...)
Creates reflection information for a specified type template.
Definition: refl.hpp:4065
refl::util::const_string::str
std::string str() const noexcept
Returns the contained string as an std::string.
Definition: refl.hpp:181
refl::attr
Contains the definitions of the built-in attributes.
Definition: refl.hpp:1883
refl::descriptor::get_display_name_const
constexpr auto get_display_name_const(Descriptor d) noexcept
Returns the display name of T as a const_string<N>.
Definition: refl.hpp:3323
refl::attr::usage
Contains a number of constraints applicable to refl-cpp attributes.
Definition: refl.hpp:1892
refl::descriptor::is_static
constexpr auto is_static(FieldDescriptor d) noexcept
Checks whether the field is declared as static.
Definition: refl.hpp:2795
refl::runtime::debug_all
void debug_all(std::basic_ostream< CharT > &os, const Ts &... values)
Writes the compact debug representation of the provided values to the given std::ostream.
Definition: refl.hpp:3818
refl::runtime::debug_all_str
std::basic_string< CharT > debug_all_str(const Ts &... values)
Writes the compact debug representation of the provided values to an std::string and returns it.
Definition: refl.hpp:3840
refl::util::make_const
constexpr const T & make_const(T &value) noexcept
Adds const to the input reference.
Definition: refl.hpp:1474
refl::attr::usage::any
Specifies that an attribute type inheriting from this type can only be used with any one of REFL_TYPE...
Definition: refl.hpp:1922
refl::util::find_first
constexpr auto find_first(type_list< Ts... > list, F &&f)
Returns the first instance that matches the constexpr predicate.
Definition: refl.hpp:1716
REFL_MAKE_CONST_STRING
#define REFL_MAKE_CONST_STRING(CString)
Converts a compile-time available const char* value to a const_string<N>.
Definition: refl.hpp:103
refl::descriptor::function_descriptor::can_resolve
static constexpr bool can_resolve()
Whether the pointer can be resolved as with the specified type.
Definition: refl.hpp:2460
refl::attr::debug::debug
constexpr debug(F write)
Definition: refl.hpp:1952
refl::util::make_const_string
constexpr const_string< 0 > make_const_string() noexcept
Creates an empty instance of const_string<N>
Definition: refl.hpp:271
refl::util::unreflect_types
constexpr type_list< Ts... > unreflect_types(type_list< descriptor::type_descriptor< Ts >... >) noexcept
Converts a type_list of type_descriptors to a type_list of the target types.
Definition: refl.hpp:1861
refl::util::operator==
constexpr bool operator==(const const_string< N > &a, const const_string< M > &b) noexcept
Compares two const_strings for equality.
Definition: refl.hpp:342
refl::util::type_list::size
static constexpr intptr_t size
The number of types in this type_list.
Definition: refl.hpp:458
refl::util::const_string::substr
constexpr auto substr() const noexcept
A constexpr version of std::string::substr.
Definition: refl.hpp:195
refl::util::find_one
constexpr auto find_one(type_list< Ts... > list, F &&f)
Returns the only instance that matches the constexpr predicate.
Definition: refl.hpp:1729
refl::trait::as_tuple< T< Ts... > >::type
std::tuple< Ts... > type
Definition: refl.hpp:837
refl::descriptor::get_attribute
constexpr const A & get_attribute(Descriptor d) noexcept
Returns the value of the attribute A on T.
Definition: refl.hpp:2984
refl::trait::is_reflectable
Checks whether there is reflection metadata for the type T.
Definition: refl.hpp:656
refl::util::ignore
constexpr int ignore(Ts &&...) noexcept
Ignores all parameters.
Definition: refl.hpp:1446
refl::descriptor::get_bases
constexpr auto get_bases(TypeDescriptor t) noexcept
Returns a list of the type_descriptor<T>s of the base types of the target, as specified by the bases<...
Definition: refl.hpp:3144
refl::runtime::debug
void debug(std::basic_ostream< CharT > &os, const T &value, [[maybe_unused]] bool compact)
Writes the debug representation of value to the given std::ostream.
Definition: refl.hpp:3806
refl::util::const_string
Represents a compile-time string.
Definition: refl.hpp:117
refl::trait::is_proxy::value
static constexpr bool value
Definition: refl.hpp:3639
refl::descriptor::get_reader
constexpr auto get_reader(WritableMember member)
Returns a member that has the same display name as the one provied and is readable.
Definition: refl.hpp:3397
refl::descriptor::is_writable
constexpr bool is_writable(MemberDescriptor) noexcept
Checks if T is a 1-arg non-const-qualified member function with a property attribute or a non-const f...
Definition: refl.hpp:3088
refl::attr::base_types::list
static constexpr list_type list
An instance of a type_list of the base types.
Definition: refl.hpp:1968
refl::util::get
constexpr auto & get(std::tuple< Ts... > &ts) noexcept
A synonym for std::get<N>(tuple).
Definition: refl.hpp:1796
refl::util
Contains utility types and functions for working with those types.
Definition: refl.hpp:95
refl::util::const_string::string
operator std::string() const noexcept
Explicitly converts to std::string.
Definition: refl.hpp:165
refl::trait::as_type_list< T< Ts... > >::type
type_list< Ts... > type
Definition: refl.hpp:803
REFL_DETAIL_GROUP
#define REFL_DETAIL_GROUP(...)
Used to group input containing commas (e.g.
Definition: refl.hpp:4016
refl::descriptor::field_descriptor::get
static constexpr decltype(auto) get(U &&target) noexcept
Returns the value of the field.
Definition: refl.hpp:2385
refl::trait::is_instance
Detects whether T is a template specialization.
Definition: refl.hpp:1169
refl::util::operator+
constexpr const_string< N+M - 1 > operator+(const const_string< N > &a, const char(&b)[M]) noexcept
Concatenates a const_string with a C-style string.
Definition: refl.hpp:320
refl::runtime::debug_str
std::basic_string< CharT > debug_str(const T &value, bool compact=false)
Writes the debug representation of the provided value to an std::string and returns it.
Definition: refl.hpp:3829
refl::descriptor::function_descriptor::is_resolved
static constexpr bool is_resolved
Whether the pointer member was correctly resolved to a concrete implementation.
Definition: refl.hpp:2453
refl::descriptor::type_descriptor::type
T type
The reflected type T.
Definition: refl.hpp:2501
refl::trait::is_type_v
constexpr bool is_type_v
Detects whether the type T is a type_descriptor.
Definition: refl.hpp:2072
refl::descriptor::member_descriptor_base::declarator
static constexpr type_descriptor< T > declarator
The type_descriptor of the declaring type.
Definition: refl.hpp:2307
refl::util::operator!=
constexpr bool operator!=(const char(&a)[N], const const_string< M > &b) noexcept
Compares a C-style string with a const_string for equality.
Definition: refl.hpp:407
REFL_DETAIL_FORCE_EBO
#define REFL_DETAIL_FORCE_EBO
Definition: refl.hpp:3451
refl::descriptor::field_descriptor::pointer
static constexpr auto pointer
A member pointer to the reflected field of the appropriate type.
Definition: refl.hpp:2362
refl::descriptor::member_descriptor_base::attribute_types
trait::as_type_list_t< std::remove_cv_t< decltype(member::attributes)> > attribute_types
An alias specifying the types of the attributes of the member.
Definition: refl.hpp:2301
refl::trait
Provides type-level operations for refl-cpp related use-cases.
Definition: refl.hpp:616
refl::descriptor::get_declared_members
constexpr auto get_declared_members(TypeDescriptor t) noexcept
Returns a type_list of the declared members of the type.
Definition: refl.hpp:2688
refl::descriptor::type_descriptor::declared_base_types
detail::declared_base_type_list< T >::type declared_base_types
The declared base types (via base_types<Ts...> attribute) of T.
Definition: refl.hpp:2507
refl::trait::is_type
Detects whether the type T is a type_descriptor.
Definition: refl.hpp:2063
refl::descriptor::is_resolved
constexpr auto is_resolved(FunctionDescriptor d) noexcept
Checks whether the function pointer was automatically resolved.
Definition: refl.hpp:2843
refl::member
Contains tag types denoting the different types of reflectable members.
Definition: refl.hpp:579
refl::runtime::proxy::proxy
constexpr proxy() noexcept
Definition: refl.hpp:3605
refl::descriptor::function_descriptor::pointer
static constexpr auto pointer
Returns a pointer to a non-overloaded function.
Definition: refl.hpp:2446
refl::member::field
An empty type which is equivalent to refl::member_descriptor_base::member_type when the reflected mem...
Definition: refl.hpp:587
refl::descriptor::get_attribute_types
constexpr auto get_attribute_types(Descriptor d) noexcept
Returns a type_list of the descriptor's attribute types.
Definition: refl.hpp:2621
refl::descriptor::get_pointer
constexpr auto get_pointer(MemberDescriptor d) noexcept
Returns a pointer to the reflected field/function.
Definition: refl.hpp:2752
refl::descriptor::get_debug_name_const
constexpr auto get_debug_name_const(MemberDescriptor d)
Returns the debug name of T (In the form of 'declaring_type::member_name') as a const_string.
Definition: refl.hpp:3184
refl::runtime::proxy
struct REFL_DETAIL_FORCE_EBO proxy
Definition: refl.hpp:3461
refl::descriptor::member_descriptor_base
The base type for member descriptors.
Definition: refl.hpp:2274
refl::descriptor::get_declared_base_types
constexpr auto get_declared_base_types(TypeDescriptor t) noexcept
Returns a type_list of the declared base types of the type.
Definition: refl.hpp:2644
refl::util::operator==
constexpr bool operator==(const const_string< N > &a, const char(&b)[M]) noexcept
Compares a const_string with a C-style string for equality.
Definition: refl.hpp:374
refl::trait::is_descriptor
A trait for detecting whether the type 'T' is a refl-cpp descriptor.
Definition: refl.hpp:2078
refl::descriptor::member_descriptor_base::member
refl::detail::member_info< T, N > member
Definition: refl.hpp:2278
refl::util::const_string::npos
static constexpr size_t npos
The largest positive value size_t can hold.
Definition: refl.hpp:120
refl::descriptor::member_descriptor_base::declaring_type
T declaring_type
An alias for the declaring type of the reflected member.
Definition: refl.hpp:2292
refl::attr::base_types::list_type
type_list< Ts... > list_type
An alias for a type_list of the base types.
Definition: refl.hpp:1965
REFL_DETAIL_STR
#define REFL_DETAIL_STR(...)
Used to stringify input separated by commas (e.g.
Definition: refl.hpp:4014
refl::util::contains
constexpr bool contains(type_list< T, Ts... > list, F &&f)
Returns true if any item in the list matches the predicate.
Definition: refl.hpp:1742
refl::util::const_string::rfind
constexpr auto rfind(char ch, size_t pos=npos) const noexcept
Searches the string for the last occurrence of the character and returns its position.
Definition: refl.hpp:234
refl::attr::usage::member
Specifies that an attribute type inheriting from this type can only be used with REFL_FUNC or REFL_FI...
Definition: refl.hpp:1916
refl::descriptor::get_members
constexpr auto get_members(TypeDescriptor t) noexcept
Returns a type_list of the declared and inherited members of the type.
Definition: refl.hpp:2709
refl::attr::property::property
constexpr property(const char *friendly_name) noexcept
Definition: refl.hpp:1938
refl::descriptor::member_descriptor_base::name
static constexpr auto name
The name of the reflected member.
Definition: refl.hpp:2313
refl::util::reflect_types
constexpr type_list< descriptor::type_descriptor< Ts >... > reflect_types(type_list< Ts... >) noexcept
Converts a type_list of types to a type_list of the type_descriptors for these types.
Definition: refl.hpp:1848
refl::is_reflectable
constexpr bool is_reflectable(const T &) noexcept
Returns true if the non-qualified type T is reflectable.
Definition: refl.hpp:3428
refl::util::as_type_list
constexpr type_list< Ts... > as_type_list(const std::tuple< Ts... > &) noexcept
Creates a matching type_list from a std::tuple.
Definition: refl.hpp:1534
refl::util::to_array
constexpr std::array< T, sizeof...(Ts)> to_array(const std::tuple< Ts... > &tuple) noexcept
Creates an array of type 'T' from the provided tuple.
Definition: refl.hpp:1485
refl::util::type_list
Represents a compile-time list of types provided as variadic template parameters.
Definition: refl.hpp:455
refl::util::map_to_array
constexpr auto map_to_array(type_list< Ts... > list, F &&f)
Applies function F to each type in the type_list, aggregating the results in an array.
Definition: refl.hpp:1608
refl::descriptor::field_descriptor::is_writable
static constexpr bool is_writable
Whether the field is const or not.
Definition: refl.hpp:2356
refl::trait::is_member
A trait for detecting whether the type 'T' is a member descriptor.
Definition: refl.hpp:2004
refl::attr::usage::type
Specifies that an attribute type inheriting from this type can only be used with REFL_TYPE()
Definition: refl.hpp:1898
refl::util::operator!=
constexpr bool operator!=(const const_string< N > &a, const const_string< M > &b) noexcept
Compares two const_strings for equality.
Definition: refl.hpp:363
refl::trait::reverse
Reverses a list of types.
Definition: refl.hpp:969
refl::descriptor::field_descriptor::value_type
member::value_type value_type
Type value type of the member.
Definition: refl.hpp:2330
refl
The top-level refl-cpp namespace It contains a few core refl-cpp namespaces and directly exposes core...
Definition: refl.hpp:90
refl::util::accumulate
constexpr auto accumulate(type_list< T, Ts... >, F &&f, R &&initial_value)
Definition: refl.hpp:1650
refl::util::get_instance
constexpr const auto & get_instance(const std::tuple< Ts... > &ts) noexcept
Returns the value of type U, where U is a template instance of T.
Definition: refl.hpp:1833
refl::descriptor::function_descriptor::resolve
static constexpr auto resolve()
Resolves the function pointer as being of type Pointer.
Definition: refl.hpp:2472
refl::descriptor::is_type
constexpr bool is_type(Descriptor) noexcept
Checks whether T is a type descriptor.
Definition: refl.hpp:2939
refl::trait::unique
Creates a new list containing the repeating elements in the source list only once.
Definition: refl.hpp:1427
refl::descriptor::function_descriptor::invoke
static constexpr auto invoke(Args &&... args) -> decltype(member::invoke(std::declval< Args >()...))
Invokes the function with the given arguments.
Definition: refl.hpp:2420
refl::descriptor
Contains the basic reflection primitives as well as functions operating on those primitives.
Definition: refl.hpp:598
refl::descriptor::get_base_types
constexpr auto get_base_types(TypeDescriptor t) noexcept
Returns a type_list of the declared and inherited base types of the type.
Definition: refl.hpp:2667
refl::descriptor::has_bases
constexpr auto has_bases(TypeDescriptor t) noexcept
Checks if a type has a bases attribute.
Definition: refl.hpp:3124
refl::descriptor::type_descriptor::declared_bases
static constexpr declared_base_types declared_bases
The declared base types (via base_types<Ts...> attribute) of T.
Definition: refl.hpp:2537
refl::attr::property::property
constexpr property() noexcept
Definition: refl.hpp:1933
refl::reflect
constexpr type_descriptor< T > reflect() noexcept
Returns the type descriptor for the type T.
Definition: refl.hpp:3435
refl::descriptor::type_descriptor::members
static constexpr member_types members
The list of declared and inherited member descriptors.
Definition: refl.hpp:2555
refl::util::operator!=
constexpr bool operator!=(const const_string< N > &a, const char(&b)[M]) noexcept
Compares a const_string with a C-style string for equality.
Definition: refl.hpp:385
refl::descriptor::is_function
constexpr bool is_function(Descriptor) noexcept
Checks whether T is a function descriptor.
Definition: refl.hpp:2922
refl::descriptor::field_descriptor::is_static
static constexpr bool is_static
Whether the field is static or not.
Definition: refl.hpp:2350
refl::util::const_string::c_str
constexpr const char * c_str() const noexcept
Returns a pointer to the contained zero-terminated string.
Definition: refl.hpp:173
REFL_DETAIL_ATTRIBUTES
#define REFL_DETAIL_ATTRIBUTES(DeclType,...)
Expands to the appropriate attributes static member variable.
Definition: refl.hpp:4023
refl::descriptor::type_descriptor::base_types
detail::base_type_list< T >::type base_types
The declared and inherited base types of T.
Definition: refl.hpp:2513
refl::util::filter
constexpr auto filter(type_list< Ts... > list, F &&f)
Filters the list according to a constexpr predicate.
Definition: refl.hpp:1706
refl::runtime::invoke
U invoke(T &&target, const char *name, Args &&... args)
Invokes the specified member with the provided arguments.
Definition: refl.hpp:3854
refl::attr::usage::field
Specifies that an attribute type inheriting from this type can only be used with REFL_FIELD()
Definition: refl.hpp:1910
refl::trait::append
Appends a type to the list.
Definition: refl.hpp:1034
refl::util::operator+
constexpr const_string< N+M > operator+(const const_string< N > &a, const const_string< M > &b) noexcept
Concatenates two const_strings together.
Definition: refl.hpp:304
refl::util::map_to_tuple
constexpr auto map_to_tuple(type_list< Ts... > list, F &&f)
Applies function F to each type in the type_list, aggregating the results in a tuple.
Definition: refl.hpp:1591
refl::util::type_list< T >::type
T type
Definition: refl.hpp:464
refl::descriptor::get_writer
constexpr auto get_writer(ReadableMember member)
Returns a member that has the same display name as the one provied and is writable.
Definition: refl.hpp:3376
std
Definition: refl.hpp:37
refl::util::make_const_string
constexpr const_string< 1 > make_const_string(char ch) noexcept
Creates an instance of const_string<N>
Definition: refl.hpp:292
refl::trait::is_container
Checks whether objects of the type T support member .begin() and .end() operations.
Definition: refl.hpp:684
refl::util::get
constexpr T & get(std::tuple< Ts... > &ts) noexcept
A synonym for std::get<T>(tuple).
Definition: refl.hpp:1810
refl::descriptor::is_property
constexpr bool is_property(MemberDescriptor d) noexcept
Checks whether T is a member descriptor marked with the property attribute.
Definition: refl.hpp:3017
refl::trait::is_field
A trait for detecting whether the type 'T' is a field descriptor.
Definition: refl.hpp:2026
REFL_DETAIL_TYPE_BODY
#define REFL_DETAIL_TYPE_BODY(TypeName,...)
Expands to the body of a type_info__ specialization.
Definition: refl.hpp:4029
refl::util::to_tuple
constexpr auto to_tuple(const std::array< T, N > &array) noexcept
Creates a tuple from the provided array.
Definition: refl.hpp:1514
refl::util::operator==
constexpr bool operator==(const char(&a)[N], const const_string< M > &b) noexcept
Compares a C-style string with a const_string for equality.
Definition: refl.hpp:396
refl::descriptor::type_descriptor::name
static constexpr const auto name
The name of the reflected type.
Definition: refl.hpp:2561
refl::util::type_list< T >::size
static constexpr intptr_t size
Definition: refl.hpp:465
refl::descriptor::get_display_name
const char * get_display_name(Descriptor d) noexcept
Returns the display name of T.
Definition: refl.hpp:3310
refl::descriptor::has_attribute
constexpr bool has_attribute(Descriptor) noexcept
Checks whether T has an attribute of type A.
Definition: refl.hpp:2954
refl::util::contains_instance
constexpr bool contains_instance(const std::tuple< Ts... > &)
Returns true if the tuple contains an instance of the specified type.
Definition: refl.hpp:1773
REFL_DETAIL_STR_IMPL
#define REFL_DETAIL_STR_IMPL(...)
Definition: refl.hpp:4012
refl::descriptor::type_descriptor::member_types
member_list< T > member_types
A synonym for member_list<T>.
Definition: refl.hpp:2525
refl::util::make_const_string
constexpr const_string< N - 1 > make_const_string(const char(&str)[N]) noexcept
Creates an instance of const_string<N>
Definition: refl.hpp:282
refl::util::const_string::const_string
constexpr const_string() noexcept
Creates an empty const_string.
Definition: refl.hpp:133
refl::descriptor::get_property
constexpr attr::property get_property(FunctionDescriptor d) noexcept
Gets the property attribute.
Definition: refl.hpp:3035
refl::descriptor::get_attribute
constexpr const auto & get_attribute(Descriptor d) noexcept
Returns the value of the attribute A on T.
Definition: refl.hpp:2999
refl::descriptor::get_name
constexpr auto get_name(Descriptor d) noexcept
Returns the full name of the descriptor.
Definition: refl.hpp:2587
refl::util::const_string::const_string
constexpr const_string(const char(&data)[N+1]) noexcept
Creates a const_string by copying the contents of data.
Definition: refl.hpp:149
refl::attr::base_types
Used to specify the base types of the target type.
Definition: refl.hpp:1962
refl::util::const_string::operator const char *
constexpr operator const char *() const noexcept
Explicitly converts to const char*.
Definition: refl.hpp:157
refl::descriptor::has_reader
constexpr auto has_reader(WritableMember member)
Checks if there exists a member that has the same display name as the one provied and is readable.
Definition: refl.hpp:3356
refl::descriptor::get_simple_name
constexpr auto get_simple_name(TypeDescriptor t)
Returns the unqualified name of the type, discarding the namespace and typenames (if a template type)...
Definition: refl.hpp:3162
refl::descriptor::type_descriptor::attributes
static constexpr const auto attributes
The attributes of the reflected type.
Definition: refl.hpp:2567
refl::descriptor::is_field
constexpr bool is_field(Descriptor) noexcept
Checks whether T is a field descriptor.
Definition: refl.hpp:2904
refl::member::function
An empty type which is equivalent to refl::member_descriptor_base::member_type when the reflected mem...
Definition: refl.hpp:595
refl::trait::remove_qualifiers
Removes all reference and cv-qualifiers from T.
Definition: refl.hpp:623
refl::descriptor::is_const
constexpr auto is_const(FieldDescriptor d) noexcept
Checks whether the value type of the field is const-qualified.
Definition: refl.hpp:2815
REFL_TYPE
#define REFL_TYPE(TypeName,...)
Creates reflection information for a specified type.
Definition: refl.hpp:4048
refl::descriptor::member_descriptor_base::attributes
static constexpr auto attributes
The attributes of the reflected member.
Definition: refl.hpp:2319
refl::descriptor::has_writer
constexpr auto has_writer(ReadableMember member)
Checks if there exists a member that has the same display name as the one provied and is writable.
Definition: refl.hpp:3336
refl::util::make_const
constexpr const T & make_const(const T &value) noexcept
Adds const to the input reference.
Definition: refl.hpp:1465
refl::util::const_string::data
char data[N+1]
The statically-sized character buffer used for storing the string.
Definition: refl.hpp:128
refl::trait::is_function
A trait for detecting whether the type 'T' is a function descriptor.
Definition: refl.hpp:2048
refl::descriptor::member_descriptor_base::member_type
member::member_type member_type
An alias specifying the member type of member.
Definition: refl.hpp:2295
refl::attr::property::friendly_name
const std::optional< const char * > friendly_name
Definition: refl.hpp:1931
refl::descriptor::get_declarator
constexpr auto get_declarator(MemberDescriptor d) noexcept
Returns the type_descriptor of declaring type of the member.
Definition: refl.hpp:2727
refl::runtime
Contains utilities that can have runtime-overhead (like proxy, debug, invoke)
Definition: refl.hpp:3458
refl::attr::debug
Used to specify how a type should be displayed in debugging contexts.
Definition: refl.hpp:1948
refl::util::contains_base
constexpr bool contains_base(const std::tuple< Ts... > &)
Returns true if the tuple contains the specified type or a supertype.
Definition: refl.hpp:1763
refl::util::get_instance
constexpr auto & get_instance(std::tuple< Ts... > &ts) noexcept
Returns the value of type U, where U is a template instance of T.
Definition: refl.hpp:1824
refl::util::identity
constexpr decltype(auto) identity(T &&t) noexcept
Returns the input paratemeter as-is.
Definition: refl.hpp:1456
refl::attr::usage::function
Specifies that an attribute type inheriting from this type can only be used with REFL_FUNC()
Definition: refl.hpp:1904
refl::util::const_string::const_string
constexpr const_string(const const_string< N > &other) noexcept
Creates a copy of a const_string.
Definition: refl.hpp:141
refl::attr::property
Used to decorate a function that serves as a property.
Definition: refl.hpp:1929
refl::descriptor::can_resolve
constexpr auto can_resolve(FunctionDescriptor d) noexcept
Checks whether the function pointer can be resolved as a pointer of the specified type.
Definition: refl.hpp:2865
refl::util::for_each
constexpr void for_each(type_list< Ts... > list, F &&f)
Applies function F to each type in the type_list.
Definition: refl.hpp:1624