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