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-2025 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 return accumulate(
444 nullptr,
445 [&name](const auto ret, const auto& elem)
446 {
447 if constexpr (std::is_same_v<Value, decltype(elem.value)>)
448 {
449 return (elem.name == name) ? &elem.value : ret;
450 }
451 else
452 {
453 return ret;
454 }
455 });
456}
457
458template <typename... Es>
459template <typename Value, typename Str>
460constexpr const Value& Elements<Es...>::valueOfName(const Str& name) const
461{
462 return *valuePtrOfName<Value>(name);
463}
464
465template <typename... Es>
466template <typename Value, typename Char>
467constexpr auto Elements<Es...>::nameOfValue(const Value& val) const
468{
469 return accumulate(
470 std::basic_string_view<Char>{},
471 [&val](const auto ret, const auto& elem) { return (elem == val) ? elem.name : ret; });
472}
473
474template <typename... Es>
475template <typename Elem>
476constexpr auto Elements<Es...>::push(const Elem& elem) const
477{
478 return std::apply([&elem](const auto&... es) { return Elements<Es..., Elem>{es..., elem}; }, elems);
479}
480
481template <typename... Es>
482template <typename Elem>
483constexpr auto Elements<Es...>::insert(const Elem& elem) const
484{
485 if constexpr ((std::is_same_v<Es, Elem> || ...))
486 {
487 return *this;
488 }
489 else
490 {
491 return push(elem);
492 }
493}
494
495template <typename... Es>
496template <std::size_t Idx>
497constexpr const auto& Elements<Es...>::get() const
498{
499 return std::get<Idx>(elems);
500}
501
502//! @brief Attribute in class.
503//! @tparam Name - type of name
504//! @tparam Value - type of target value
505template <typename Name, typename Value>
506struct Attr : public NamedValue<Name, Value>
507{
508 //! @brief Construct a new Attr object.
509 //! @param val - target value
510 constexpr Attr(const Name /*name*/, const Value val) : NamedValue<Name, Value>{val} {}
511};
512
513//! @brief Attribute in class.
514//! @tparam Name - type of name
515template <typename Name>
516struct Attr<Name, void> : public NamedValue<Name, void>
517{
518 //! @brief Construct a new Attr object.
519 constexpr explicit Attr(const Name /*name*/) {}
520};
521
522//! @brief The list of attributes.
523//! @tparam As - type of list of attributes
524template <typename... As>
525struct AttrList : public Elements<As...>
526{
527 //! @brief Construct a new AttrList object.
528 //! @param as - list of attributes
529 constexpr explicit AttrList(const As... as) : Elements<As...>{as...} {}
530};
531
532//! @brief Base class of trait.
533//! @tparam IsStat - whether it is static
534//! @tparam IsFunc - whether it is a function
535template <bool IsStat, bool IsFunc>
536struct TraitBase
537{
538 //! @brief Flag to indicate whether it is static.
539 static constexpr bool isStatic{IsStat};
540 //! @brief Flag to indicate whether it is a function.
541 static constexpr bool isFunction{IsFunc};
542};
543
544//! @brief Specialization for trait.
545//! @tparam Value - type of target value
546template <typename Value>
547struct Trait : public TraitBase<true, false>
548{
549};
550
551//! @brief Specialization for trait.
552//! @tparam Obj - type of target object
553//! @tparam Value - type of target value
554template <typename Obj, typename Value>
555struct Trait<Value Obj::*> : public TraitBase<false, std::is_function_v<Value>>
556{
557};
558
559//! @brief Specialization for trait.
560//! @tparam Value - type of target value
561template <typename Value>
562struct Trait<Value*> : public TraitBase<true, std::is_function_v<Value>>
563{
564};
565
566//! @brief Field in class.
567//! @tparam Name - type of name
568//! @tparam Value - type of target value
569//! @tparam Attrs - type of list of attributes
570template <typename Name, typename Value, typename Attrs>
571struct Field : public Trait<Value>, public NamedValue<Name, Value>
572{
573 //! @brief Construct a new Field object.
574 //! @param val - target value
575 //! @param as - list of attributes
576 constexpr Field(const Name /*name*/, const Value val, const Attrs as = {}) : NamedValue<Name, Value>{val}, attrs{as}
577 {
578 }
579
580 //! @brief Attribute list.
581 const Attrs attrs{};
582};
583
584//! @brief The list of fields.
585//! @tparam Fs - type of list of fields
586template <typename... Fs>
587struct FieldList : public Elements<Fs...>
588{
589 //! @brief Construct a new FieldList object.
590 //! @param fs - list of fields
591 constexpr explicit FieldList(const Fs... fs) : Elements<Fs...>{fs...} {}
592};
593
594//! @brief Type information.
595//! @tparam UDT - type of user defined data
596template <typename UDT>
597struct TypeInfo;
598
599//! @brief Public base class.
600//! @tparam UDT - type of user defined data
601//! @tparam IsVirtual - whether it is virtual base class
602template <typename UDT, bool IsVirtual = false>
603struct Base
604{
605 //! @brief Type information.
606 static constexpr auto info{TypeInfo<UDT>{}};
607 //! @brief Flag to indicate whether it is virtual base class.
608 static constexpr bool isVirtual{IsVirtual};
609};
610
611//! @brief The list of public base classes.
612//! @tparam Bs - type of list of public base classes
613template <typename... Bs>
614struct BaseList : public Elements<Bs...>
615{
616 //! @brief Construct a new BaseList object.
617 //! @param bs - list of public base classes
618 constexpr explicit BaseList(const Bs... bs) : Elements<Bs...>{bs...} {}
619};
620
621//! @brief The list of type informations.
622//! @tparam Ts - type of list of type informations
623template <typename... Ts>
624struct TypeInfoList : public Elements<Ts...>
625{
626 //! @brief Construct a new TypeInfoList object.
627 //! @param ts - list of type informations
628 constexpr explicit TypeInfoList(const Ts... ts) : Elements<Ts...>{ts...} {}
629};
630
631//! @brief The base class that includes the implementation of type information.
632//! @tparam Info - type of type information
633//! @tparam Bs - type of list of public base classes
634template <typename Info, typename... Bs>
635class TypeInfoImpl
636{
637public:
638 //! @brief Alias for the type.
639 using Type = Info;
640 //! @brief Public base class list.
641 static constexpr BaseList bases{Bs{}...};
642
643 //! @brief Forward cast from derived object to base object.
644 //! @tparam Derived - type of derived object
645 //! @param self - derived object
646 //! @return base object
647 template <typename Derived>
648 static constexpr auto&& forward(Derived&& self);
649 //! @brief Get all virtual base objects.
650 //! @return accumulation of virtual base class
651 static constexpr auto virtualBases();
652 //! @brief Accumulating by the DFS algorithm.
653 //! @tparam Ret - type of return value
654 //! @tparam Func - type of callable function
655 //! @param ret - type of return value
656 //! @param func - callable function
657 //! @return result of accumulation
658 template <typename Ret, typename Func>
659 static constexpr auto dfsAcc(Ret ret, Func&& func);
660 //! @brief Iteration in the DFS algorithm.
661 //! @tparam Func - type of callable function
662 //! @param func - callable function
663 template <typename Func>
664 static constexpr void dfsForEach(Func&& func);
665 //! @brief Iteration variable only.
666 //! @tparam Obj - type of object to be traversed
667 //! @tparam Func - type of callable function
668 //! @param obj - object to be traversed
669 //! @param func - callable function
670 template <typename Obj, typename Func>
671 static constexpr void forEachVarOf(Obj&& obj, Func&& func);
672};
673
674template <typename Info, typename... Bs>
675template <typename Derived>
676constexpr auto&& TypeInfoImpl<Info, Bs...>::forward(Derived&& self)
677{
678 if constexpr (std::is_same_v<std::decay_t<Derived>, Derived>)
679 {
680 return static_cast<Type&&>(std::forward<Derived>(self));
681 }
682 else if constexpr (std::is_same_v<std::decay_t<Derived>&, Derived>)
683 {
684 return static_cast<Type&>(std::forward<Derived>(self));
685 }
686 else
687 {
688 return static_cast<const std::decay_t<Derived>&>(std::forward<Derived>(self));
689 }
690}
691
692template <typename Info, typename... Bs>
693constexpr auto TypeInfoImpl<Info, Bs...>::virtualBases()
694{
695 return bases.accumulate(
696 Elements<>{},
697 [](const auto acc, const auto base)
698 {
699 auto concat = base.info.virtualBases().accumulate(
700 acc, [](const auto acc, const auto base) { return acc.insert(base); });
701 if constexpr (!base.isVirtual)
702 {
703 return concat;
704 }
705 else
706 {
707 return concat.insert(base.info);
708 }
709 });
710}
711
712template <typename Info, typename... Bs>
713template <typename Ret, typename Func>
714constexpr auto TypeInfoImpl<Info, Bs...>::dfsAcc(Ret ret, Func&& func)
715{
716 return Reflect::dfsAcc<0>(
717 TypeInfo<Type>{},
718 std::forward<Func>(func),
719 virtualBases().accumulate(
720 std::forward<Func>(func)(std::move(ret), TypeInfo<Type>{}, 0),
721 [&](const auto acc, const auto vb) { return std::forward<Func>(func)(std::move(acc), vb, 1); }));
722}
723
724template <typename Info, typename... Bs>
725template <typename Func>
726constexpr void TypeInfoImpl<Info, Bs...>::dfsForEach(Func&& func)
727{
728 dfsAcc(
729 0,
730 [&](const auto /*func*/, const auto info, const auto der)
731 {
732 std::forward<Func>(func)(info, der);
733 return 0;
734 });
735}
736
737template <typename Info, typename... Bs>
738template <typename Obj, typename Func>
739constexpr void TypeInfoImpl<Info, Bs...>::forEachVarOf(Obj&& obj, Func&& func)
740{
741 virtualBases().forEach(
742 [&](const auto vb)
743 {
744 vb.fields.forEach(
745 [&](const auto fld)
746 {
747 using Fld = std::decay_t<decltype(fld)>;
748 if constexpr (!Fld::isStatic && !Fld::isFunction)
749 {
750 std::forward<Func>(func)(fld, std::forward<Obj>(obj).*(fld.value));
751 }
752 });
753 });
754 Reflect::varInNodeV(TypeInfo<Type>{}, std::forward<Obj>(obj), std::forward<Func>(func));
755}
756
757//! @brief Attribute in class.
758//! @tparam Name - type of name
759template <typename Name>
760Attr(Name) -> Attr<Name, void>;
761
762//! @brief Field in class.
763//! @tparam Name - type of name
764//! @tparam Value - type of target value
765template <typename Name, typename Value>
766Field(Name, Value) -> Field<Name, Value, AttrList<>>;
767} // namespace reflection
768} // namespace utility
769