1//! @file reflection.hpp
2//! @author ryftchen
3//! @brief The declarations (reflection) in the utility module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#pragma once
8
9#include <string_view>
10#include <tuple>
11
12//! @brief Convert target string for reflection.
13#define REFLECTION_STR(str) \
14 ( \
15 []() consteval \
16 { \
17 constexpr std::basic_string_view refl = str; \
18 return utility::reflection::Reflect::String< \
19 utility::reflection::Reflect::ReflStr<typename decltype(refl)::value_type, refl.size()>{refl}>{}; \
20 }())
21
22//! @brief The utility module.
23namespace utility // NOLINT(modernize-concat-nested-namespaces)
24{
25//! @brief Static-reflection-related functions in the utility module.
26namespace reflection
27{
28//! @brief Brief function description.
29//! @return function description (module_function)
30inline static const char* description() noexcept
31{
32 return "UTIL_REFLECTION";
33}
34extern const char* version() noexcept;
35
36//! @brief Reflection.
37class Reflect
38{
39public:
40 //! @brief Custom string type wrapper.
41 //! @tparam Char - type of character in string
42 //! @tparam Size - string size
43 template <typename Char, std::size_t Size>
44 class ReflStr
45 {
46 public:
47 //! @brief Alias for the value type.
48 using ValueType = Char;
49 //! @brief Construct a new ReflStr object.
50 //! @param str - target string
51 consteval explicit ReflStr(const std::basic_string_view<ValueType> str)
52 {
53 for (std::size_t i = 0; i < size; ++i)
54 {
55 data[i] = str[i];
56 }
57 }
58
59 //! @brief String data.
60 ValueType data[Size + 1]{};
61 //! @brief String size.
62 static constexpr std::size_t size{Size};
63 };
64
65 //! @brief Custom string.
66 //! @tparam Str - custom string with wrapper
67 template <ReflStr Str>
68 class String
69 {
70 public:
71 //! @brief Alias for the character.
72 using Char = typename decltype(Str)::ValueType;
73 //! @brief Check whether it is the custom string type.
74 //! @tparam Chars - type of target string
75 //! @return be custom string type or not
76 template <typename Chars>
77 static consteval bool is(const Chars& /*str*/ = {})
78 {
79 return std::is_same_v<Chars, String>;
80 }
81 //! @brief Get the string data.
82 //! @return string data
83 static consteval auto data() { return Str.data; }
84 //! @brief Get the string size.
85 //! @return string size
86 static consteval auto size() { return Str.size; }
87 //! @brief Get the string for view only.
88 //! @return string data for view only
89 static consteval std::basic_string_view<Char> view() { return Str.data; }
90 };
91
92 //! @brief Finding by condition.
93 //! @tparam Lit - type of string literal
94 //! @tparam Func - type of callable function
95 //! @param lit - string literal
96 //! @param func - callable function
97 //! @param seq - sequences related to arguments
98 //! @return value index
99 template <typename Lit, typename Func>
100 static constexpr std::size_t findIf(const Lit& lit, Func&& func, const std::index_sequence<>& seq);
101 //! @brief Finding by condition.
102 //! @tparam Lit - type of string literal
103 //! @tparam Func - type of callable function
104 //! @tparam I0 - current index of elements
105 //! @tparam Is - indices of sequence related to elements
106 //! @param lit - string literal
107 //! @param func - callable function
108 //! @param seq - sequence related to elements
109 //! @return value index
110 template <typename Lit, typename Func, std::size_t I0, std::size_t... Is>
111 static constexpr std::size_t findIf(const Lit& lit, Func&& func, const std::index_sequence<I0, Is...>& seq);
112 //! @brief Calculate accumulation.
113 //! @tparam Lit - type of string literal
114 //! @tparam Func - type of callable function
115 //! @tparam Ret - type of return value
116 //! @param lit - string literal
117 //! @param func - callable function
118 //! @param ret - return value
119 //! @param seq - sequences related to arguments
120 //! @return result of accumulation
121 template <typename Lit, typename Func, typename Ret>
122 static constexpr auto acc(const Lit& lit, Func&& func, Ret ret, const std::index_sequence<>& seq);
123 //! @brief Calculate accumulation.
124 //! @tparam Lit - type of string literal
125 //! @tparam Func - type of callable function
126 //! @tparam Ret - type of return value
127 //! @tparam I0 - current index of elements
128 //! @tparam Is - indices of sequence related to elements
129 //! @param lit - string literal
130 //! @param func - callable function
131 //! @param ret - return value
132 //! @param seq - sequence related to elements
133 //! @return result of accumulation
134 template <typename Lit, typename Func, typename Ret, std::size_t I0, std::size_t... Is>
135 static constexpr auto acc(const Lit& lit, Func&& func, Ret ret, const std::index_sequence<I0, Is...>& seq);
136 //! @brief Calculate accumulation by the DFS algorithm.
137 //! @tparam Depth - degree of depth
138 //! @tparam Info - type of type information
139 //! @tparam Ret - type of return value
140 //! @tparam Func - type of callable function
141 //! @param info - type information
142 //! @param func - callable function
143 //! @param ret - return value
144 //! @return result of the accumulation
145 template <std::size_t Depth, typename Info, typename Ret, typename Func>
146 static constexpr auto dfsAcc(const Info& info, Func&& func, Ret ret);
147 //! @brief Traverse the variable of node v in the DFS algorithm.
148 //! @tparam Info - type of type information
149 //! @tparam Obj - type of object to be traversed
150 //! @tparam Func - type of callable function
151 //! @param info - type information
152 //! @param obj - object to be traversed
153 //! @param func - callable function
154 template <typename Info, typename Obj, typename Func>
155 static constexpr void varInNodeV(const Info& info, Obj&& obj, Func&& func);
156};
157
158template <typename Lit, typename Func>
159constexpr std::size_t Reflect::findIf(const Lit& /*lit*/, Func&& /*func*/, const std::index_sequence<>& /*seq*/)
160{
161 return -1;
162}
163
164template <typename Lit, typename Func, std::size_t I0, std::size_t... Is>
165constexpr std::size_t Reflect::findIf(const Lit& lit, Func&& func, const std::index_sequence<I0, Is...>& /*seq*/)
166{
167 return func(lit.template get<I0>()) ? I0 : findIf(lit, std::forward<Func>(func), std::index_sequence<Is...>{});
168}
169
170template <typename Lit, typename Func, typename Ret>
171constexpr auto Reflect::acc(const Lit& /*lit*/, Func&& /*func*/, Ret ret, const std::index_sequence<>& /*seq*/)
172{
173 return ret;
174}
175
176template <typename Lit, typename Func, typename Ret, std::size_t I0, std::size_t... Is>
177constexpr auto Reflect::acc(const Lit& lit, Func&& func, Ret ret, const std::index_sequence<I0, Is...>& /*seq*/)
178{
179 return acc(
180 lit, std::forward<Func>(func), func(std::move(ret), lit.template get<I0>()), std::index_sequence<Is...>{});
181}
182
183template <std::size_t Depth, typename Info, typename Ret, typename Func>
184constexpr auto Reflect::dfsAcc(const Info& info, Func&& func, Ret ret)
185{
186 return info.bases.accumulate(
187 std::move(ret),
188 [&](const auto ret, const auto base)
189 {
190 if constexpr (base.isVirtual)
191 {
192 return dfsAcc<Depth + 1>(base.info, std::forward<Func>(func), ret);
193 }
194 else
195 {
196 return dfsAcc<Depth + 1>(
197 base.info, std::forward<Func>(func), std::forward<Func>(func)(ret, base.info, Depth + 1));
198 }
199 });
200}
201
202template <typename Info, typename Obj, typename Func>
203constexpr void Reflect::varInNodeV(const Info& /*info*/, Obj&& obj, Func&& func)
204{
205 Info::fields.forEach(
206 [&](const auto fld)
207 {
208 using Fld = std::decay_t<decltype(fld)>;
209 if constexpr (!Fld::isStatic && !Fld::isFunction)
210 {
211 std::forward<Func>(func)(fld, std::forward<Obj>(obj).*(fld.value));
212 }
213 });
214 Info::bases.forEach(
215 [&](const auto base)
216 {
217 if constexpr (!base.isVirtual)
218 {
219 varInNodeV(base.info, base.info.forward(std::forward<Obj>(obj)), std::forward<Func>(func));
220 }
221 });
222}
223
224//! @brief Base class of named value.
225//! @tparam Name - type of name
226template <typename Name>
227struct NamedValueBase
228{
229 //! @brief Alias for the name type.
230 using NameType = Name;
231 //! @brief Value name.
232 static constexpr std::string_view name{NameType::view()};
233};
234
235//! @brief Specialization for named value.
236//! @tparam Name - type of name
237//! @tparam Value - type of target value
238template <typename Name, typename Value>
239struct NamedValue : public NamedValueBase<Name>
240{
241 //! @brief Construct a new NamedValue object.
242 //! @param val - target value
243 constexpr explicit NamedValue(const Value val) : value{val} {}
244
245 //! @brief The operator (==) overloading of NamedValue struct.
246 //! @tparam RHS - type of right-hand side
247 //! @param rhs - right-hand side
248 //! @return be equal or not
249 template <typename RHS>
250 constexpr bool operator==(const RHS& rhs) const
251 {
252 if constexpr (std::is_same_v<Value, RHS>)
253 {
254 return value == rhs;
255 }
256 else
257 {
258 return false;
259 }
260 }
261
262 //! @brief Named value.
263 Value value{};
264 //! @brief Flag to indicate whether it has a value.
265 static constexpr bool hasValue{true};
266};
267
268//! @brief Specialization for named value.
269//! @tparam Name - type of name
270template <typename Name>
271struct NamedValue<Name, void> : public NamedValueBase<Name>
272{
273 //! @brief The operator (==) overloading of NamedValue struct.
274 //! @tparam RHS - type of right-hand side
275 //! @return be equal or not
276 template <typename RHS>
277 constexpr bool operator==(const RHS& /*rhs*/) const
278 {
279 return false;
280 }
281
282 //! @brief Flag to indicate whether it has a value.
283 static constexpr bool hasValue{false};
284};
285
286//! @brief The list of elements.
287//! @tparam Es - type of list of elements
288template <typename... Es>
289class Elements
290{
291public:
292 //! @brief Construct a new Elements object.
293 //! @param es - list of elements
294 constexpr explicit Elements(const Es&... es) : elems{es...} {}
295
296 //! @brief Size of list of the elements.
297 static constexpr std::size_t size{sizeof...(Es)};
298 //! @brief Accumulating.
299 //! @tparam Init - type of initial accumulation
300 //! @tparam Func - type of callable function
301 //! @param init - initial accumulation
302 //! @param func - callable function
303 //! @return result of accumulation
304 template <typename Init, typename Func>
305 constexpr auto accumulate(Init init, Func&& func) const;
306 //! @brief Iteration.
307 //! @tparam Func - type of callable function
308 //! @param func - callable function
309 template <typename Func>
310 constexpr void forEach(Func&& func) const;
311 //! @brief Check whether it contains the custom string.
312 //! @tparam Str - type of custom string
313 //! @param name - value name
314 //! @return contains or not
315 template <typename Str>
316 static constexpr bool contains(const Str& name = {});
317 //! @brief Finding by condition.
318 //! @tparam Func - type of callable function
319 //! @param func - callable function
320 //! @return value index
321 template <typename Func>
322 constexpr std::size_t findIf(Func&& func) const;
323 //! @brief Finding.
324 //! @tparam Str - type of custom string
325 //! @param name - value name
326 //! @return value index
327 template <typename Str>
328 constexpr const auto& find(const Str& name = {}) const;
329 //! @brief Finding by value.
330 //! @tparam Value - type of target value
331 //! @param val - target value
332 //! @return value index
333 template <typename Value>
334 constexpr std::size_t findValue(const Value& val) const;
335 //! @brief Get the pointer of value by name.
336 //! @tparam Value - type of value
337 //! @tparam Str - type of custom string
338 //! @param name - value name
339 //! @return pointer of value
340 template <typename Value, typename Str>
341 constexpr const Value* valuePtrOfName(const Str& name) const;
342 //! @brief Get the reference of value by name.
343 //! @tparam Value - type of value
344 //! @tparam Str - type of custom string
345 //! @param name - value name
346 //! @return reference of value
347 template <typename Value, typename Str>
348 constexpr const Value& valueOfName(const Str& name) const;
349 //! @brief Get the name by value.
350 //! @tparam Value - type of target value
351 //! @tparam Char - type of character in custom string
352 //! @param val - target value
353 //! @return value name
354 template <typename Value, typename Char = char>
355 constexpr auto nameOfValue(const Value& val) const;
356 //! @brief Push operation of the element.
357 //! @tparam Elem - type of target element
358 //! @param elem - target element
359 //! @return position after pushing
360 template <typename Elem>
361 constexpr auto push(const Elem& elem) const;
362 //! @brief Insert operation of the element.
363 //! @tparam Elem - type of target element
364 //! @param elem - target element
365 //! @return position after inserting
366 template <typename Elem>
367 constexpr auto insert(const Elem& elem) const;
368 //! @brief Get the value.
369 //! @tparam Idx - value index
370 //! @return target value
371 template <std::size_t Idx>
372 constexpr const auto& get() const;
373
374private:
375 //! @brief Element list.
376 const std::tuple<Es...> elems{};
377};
378
379template <typename... Es>
380template <typename Init, typename Func>
381constexpr auto Elements<Es...>::accumulate(Init init, Func&& func) const
382{
383 return Reflect::acc(*this, std::forward<Func>(func), std::move(init), std::make_index_sequence<size>{});
384}
385
386template <typename... Es>
387template <typename Func>
388constexpr void Elements<Es...>::forEach(Func&& func) const
389{
390 accumulate(
391 0,
392 [&](const auto /*func*/, const auto fld)
393 {
394 std::forward<Func>(func)(fld);
395 return 0;
396 });
397}
398
399template <typename... Es>
400template <typename Str>
401constexpr bool Elements<Es...>::contains(const Str& /*name*/)
402{
403 return (Es::NameType::template is<Str>() || ...);
404}
405
406template <typename... Es>
407template <typename Func>
408constexpr std::size_t Elements<Es...>::findIf(Func&& func) const
409{
410 return Reflect::findIf(*this, std::forward<Func>(func), std::make_index_sequence<size>{});
411}
412
413template <typename... Es>
414template <typename Str>
415constexpr const auto& Elements<Es...>::find(const Str& /*name*/) const
416{
417 constexpr std::size_t index = []() constexpr
418 {
419 constexpr decltype(Str::view()) names[]{Es::name...};
420 for (std::size_t i = 0; i < size; ++i)
421 {
422 if (Str::view() == names[i])
423 {
424 return i;
425 }
426 }
427 return static_cast<std::size_t>(-1);
428 }();
429 return get<index>();
430}
431
432template <typename... Es>
433template <typename Value>
434constexpr std::size_t Elements<Es...>::findValue(const Value& val) const
435{
436 return findIf([&val](const auto& elem) { return elem == val; });
437}
438
439template <typename... Es>
440template <typename Value, typename Str>
441constexpr const Value* Elements<Es...>::valuePtrOfName(const Str& name) const
442{
443 const Value* ptr = nullptr;
444 std::apply(
445 [&name, &ptr](const auto&... elem) constexpr
446 {
447 (
448 [&name, &ptr, &elem]() constexpr
449 {
450 if constexpr (std::is_same_v<Value, decltype(elem.value)>)
451 {
452 if (elem.name == name)
453 {
454 ptr = &elem.value;
455 }
456 }
457 }(),
458 ...);
459 },
460 elems);
461 return ptr;
462}
463
464template <typename... Es>
465template <typename Value, typename Str>
466constexpr const Value& Elements<Es...>::valueOfName(const Str& name) const
467{
468 return *valuePtrOfName<Value>(name);
469}
470
471template <typename... Es>
472template <typename Value, typename Char>
473constexpr auto Elements<Es...>::nameOfValue(const Value& val) const
474{
475 return accumulate(
476 std::basic_string_view<Char>{},
477 [&val](const auto ret, const auto& elem) { return (elem == val) ? elem.name : ret; });
478}
479
480template <typename... Es>
481template <typename Elem>
482constexpr auto Elements<Es...>::push(const Elem& elem) const
483{
484 return std::apply([&elem](const auto&... es) { return Elements<Es..., Elem>{es..., elem}; }, elems);
485}
486
487template <typename... Es>
488template <typename Elem>
489constexpr auto Elements<Es...>::insert(const Elem& elem) const
490{
491 if constexpr ((std::is_same_v<Es, Elem> || ...))
492 {
493 return *this;
494 }
495 else
496 {
497 return push(elem);
498 }
499}
500
501template <typename... Es>
502template <std::size_t Idx>
503constexpr const auto& Elements<Es...>::get() const
504{
505 return std::get<Idx>(elems);
506}
507
508//! @brief Attribute in class.
509//! @tparam Name - type of name
510//! @tparam Value - type of target value
511template <typename Name, typename Value>
512struct Attr : public NamedValue<Name, Value>
513{
514 //! @brief Construct a new Attr object.
515 //! @param val - target value
516 constexpr Attr(const Name /*name*/, const Value val) : NamedValue<Name, Value>{val} {}
517};
518
519//! @brief Attribute in class.
520//! @tparam Name - type of name
521template <typename Name>
522struct Attr<Name, void> : public NamedValue<Name, void>
523{
524 //! @brief Construct a new Attr object.
525 constexpr explicit Attr(const Name /*name*/) {}
526};
527
528//! @brief The list of attributes.
529//! @tparam As - type of list of attributes
530template <typename... As>
531struct AttrList : public Elements<As...>
532{
533 //! @brief Construct a new AttrList object.
534 //! @param as - list of attributes
535 constexpr explicit AttrList(const As... as) : Elements<As...>{as...} {}
536};
537
538//! @brief Base class of trait.
539//! @tparam IsStat - whether it is static
540//! @tparam IsFunc - whether it is a function
541template <bool IsStat, bool IsFunc>
542struct TraitBase
543{
544 //! @brief Flag to indicate whether it is static.
545 static constexpr bool isStatic{IsStat};
546 //! @brief Flag to indicate whether it is a function.
547 static constexpr bool isFunction{IsFunc};
548};
549
550//! @brief Specialization for trait.
551//! @tparam Value - type of target value
552template <typename Value>
553struct Trait : public TraitBase<true, false>
554{
555};
556
557//! @brief Specialization for trait.
558//! @tparam Obj - type of target object
559//! @tparam Value - type of target value
560template <typename Obj, typename Value>
561struct Trait<Value Obj::*> : public TraitBase<false, std::is_function_v<Value>>
562{
563};
564
565//! @brief Specialization for trait.
566//! @tparam Value - type of target value
567template <typename Value>
568struct Trait<Value*> : public TraitBase<true, std::is_function_v<Value>>
569{
570};
571
572//! @brief Field in class.
573//! @tparam Name - type of name
574//! @tparam Value - type of target value
575//! @tparam Attrs - type of list of attributes
576template <typename Name, typename Value, typename Attrs>
577struct Field : public Trait<Value>, public NamedValue<Name, Value>
578{
579 //! @brief Construct a new Field object.
580 //! @param val - target value
581 //! @param as - list of attributes
582 constexpr Field(const Name /*name*/, const Value val, const Attrs as = {}) : NamedValue<Name, Value>{val}, attrs{as}
583 {
584 }
585
586 //! @brief Attribute list.
587 const Attrs attrs{};
588};
589
590//! @brief The list of fields.
591//! @tparam Fs - type of list of fields
592template <typename... Fs>
593struct FieldList : public Elements<Fs...>
594{
595 //! @brief Construct a new FieldList object.
596 //! @param fs - list of fields
597 constexpr explicit FieldList(const Fs&... fs) : Elements<Fs...>{fs...} {}
598};
599
600//! @brief Type information.
601//! @tparam UDT - type of user defined data
602template <typename UDT>
603struct TypeInfo;
604
605//! @brief Public base class.
606//! @tparam UDT - type of user defined data
607//! @tparam IsVirtual - whether it is virtual base class
608template <typename UDT, bool IsVirtual = false>
609struct Base
610{
611 //! @brief Type information.
612 static constexpr auto info{TypeInfo<UDT>{}};
613 //! @brief Flag to indicate whether it is virtual base class.
614 static constexpr bool isVirtual{IsVirtual};
615};
616
617//! @brief The list of public base classes.
618//! @tparam Bs - type of list of public base classes
619template <typename... Bs>
620struct BaseList : public Elements<Bs...>
621{
622 //! @brief Construct a new BaseList object.
623 //! @param bs - list of public base classes
624 constexpr explicit BaseList(const Bs... bs) : Elements<Bs...>{bs...} {}
625};
626
627//! @brief The list of type informations.
628//! @tparam Ts - type of list of type informations
629template <typename... Ts>
630struct TypeInfoList : public Elements<Ts...>
631{
632 //! @brief Construct a new TypeInfoList object.
633 //! @param ts - list of type informations
634 constexpr explicit TypeInfoList(const Ts... ts) : Elements<Ts...>{ts...} {}
635};
636
637//! @brief The base class that includes the implementation of type information.
638//! @tparam Info - type of type information
639//! @tparam Bs - type of list of public base classes
640template <typename Info, typename... Bs>
641class TypeInfoImpl
642{
643public:
644 //! @brief Alias for the type.
645 using Type = Info;
646 //! @brief Public base class list.
647 static constexpr BaseList bases{Bs{}...};
648
649 //! @brief Forward cast from derived object to base object.
650 //! @tparam Derived - type of derived object
651 //! @param self - derived object
652 //! @return base object
653 template <typename Derived>
654 static constexpr auto&& forward(Derived&& self);
655 //! @brief Get all virtual base objects.
656 //! @return accumulation of virtual base class
657 static constexpr auto virtualBases();
658 //! @brief Accumulating by the DFS algorithm.
659 //! @tparam Ret - type of return value
660 //! @tparam Func - type of callable function
661 //! @param ret - type of return value
662 //! @param func - callable function
663 //! @return result of accumulation
664 template <typename Ret, typename Func>
665 static constexpr auto dfsAcc(Ret ret, Func&& func);
666 //! @brief Iteration in the DFS algorithm.
667 //! @tparam Func - type of callable function
668 //! @param func - callable function
669 template <typename Func>
670 static constexpr void dfsForEach(Func&& func);
671 //! @brief Iteration variable only.
672 //! @tparam Obj - type of object to be traversed
673 //! @tparam Func - type of callable function
674 //! @param obj - object to be traversed
675 //! @param func - callable function
676 template <typename Obj, typename Func>
677 static constexpr void forEachVarOf(Obj&& obj, Func&& func);
678};
679
680template <typename Info, typename... Bs>
681template <typename Derived>
682constexpr auto&& TypeInfoImpl<Info, Bs...>::forward(Derived&& self)
683{
684 if constexpr (std::is_same_v<std::decay_t<Derived>, Derived>)
685 {
686 return static_cast<Type&&>(std::forward<Derived>(self));
687 }
688 else if constexpr (std::is_same_v<std::decay_t<Derived>&, Derived>)
689 {
690 return static_cast<Type&>(std::forward<Derived>(self));
691 }
692 else
693 {
694 return static_cast<const std::decay_t<Derived>&>(std::forward<Derived>(self));
695 }
696}
697
698template <typename Info, typename... Bs>
699constexpr auto TypeInfoImpl<Info, Bs...>::virtualBases()
700{
701 return bases.accumulate(
702 Elements<>{},
703 [](const auto acc, const auto base)
704 {
705 auto concat = base.info.virtualBases().accumulate(
706 acc, [](const auto acc, const auto base) { return acc.insert(base); });
707 if constexpr (!base.isVirtual)
708 {
709 return concat;
710 }
711 else
712 {
713 return concat.insert(base.info);
714 }
715 });
716}
717
718template <typename Info, typename... Bs>
719template <typename Ret, typename Func>
720constexpr auto TypeInfoImpl<Info, Bs...>::dfsAcc(Ret ret, Func&& func)
721{
722 return Reflect::dfsAcc<0>(
723 TypeInfo<Type>{},
724 std::forward<Func>(func),
725 virtualBases().accumulate(
726 std::forward<Func>(func)(std::move(ret), TypeInfo<Type>{}, 0),
727 [&](const auto acc, const auto vb) { return std::forward<Func>(func)(std::move(acc), vb, 1); }));
728}
729
730template <typename Info, typename... Bs>
731template <typename Func>
732constexpr void TypeInfoImpl<Info, Bs...>::dfsForEach(Func&& func)
733{
734 dfsAcc(
735 0,
736 [&](const auto /*func*/, const auto info, const auto der)
737 {
738 std::forward<Func>(func)(info, der);
739 return 0;
740 });
741}
742
743template <typename Info, typename... Bs>
744template <typename Obj, typename Func>
745constexpr void TypeInfoImpl<Info, Bs...>::forEachVarOf(Obj&& obj, Func&& func)
746{
747 virtualBases().forEach(
748 [&](const auto vb)
749 {
750 vb.fields.forEach(
751 [&](const auto fld)
752 {
753 using Fld = std::decay_t<decltype(fld)>;
754 if constexpr (!Fld::isStatic && !Fld::isFunction)
755 {
756 std::forward<Func>(func)(fld, std::forward<Obj>(obj).*(fld.value));
757 }
758 });
759 });
760 Reflect::varInNodeV(TypeInfo<Type>{}, std::forward<Obj>(obj), std::forward<Func>(func));
761}
762
763//! @brief Attribute in class.
764//! @tparam Name - type of name
765template <typename Name>
766Attr(Name) -> Attr<Name, void>;
767
768//! @brief Field in class.
769//! @tparam Name - type of name
770//! @tparam Value - type of target value
771template <typename Name, typename Value>
772Field(Name, Value) -> Field<Name, Value, AttrList<>>;
773} // namespace reflection
774} // namespace utility
775