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