1- # Magic Cpp
1+ ![ cover ] ( docs/assets/cover.png )
22
3- Header-only C++20 library provides static reflection for type, aggregate class and enum, no external dependencies, no registration, no macro, no code generation, just magic.
3+ magic-cpp is C++20 header-only library provides static reflection for type, struct and enum, no external dependencies, no registration, no macro, no code generation.
44
5- ## Documentation
5+ # Documentation
66* [ Reference] ( doc/reference.md )
77* [ Limitations] ( doc/limitations.md )
88* [ Integration] ( #Integration )
99
10- ## [ Examples] ( example/ )
11- ### type
10+ # [ Examples] ( example/ )
11+ ## type
1212
13- * just include ` magic/type.h ` to use these features*
13+ ** just include ` magic/type.h ` to use the features below * *
1414
15- * full name of type
15+ - * retrieve the full name of a type * :
1616``` cpp
1717struct Point {};
18+
1819constexpr auto name = magic::full_name_of<Point>();
19- static_assert ( name == " Point" );
20+ // name => "Point"
2021
2122constexpr auto name2 = magic::full_name_of<std::vector<int >>();
22- static_assert ( name2 == " std::vector<int, std::allocator<int>> " );
23+ // name2 => "std::vector<int>"
2324
2425constexpr auto name3 = magic::full_name_of<std::size_t >();
25- static_assert ( name3 == " unsigned long long int" );
26+ // name3 => "unsigned long long int"
2627```
27- * display name of type
28+ - * retrieve the display name of a type*
2829``` cpp
29- // specialization for type to get better readable
30- namespace magic
30+ // specialize for type to customize the display name
31+ template <>
32+ struct magic ::type_info< std::size_t >
3133{
32- template<>
33- struct type_info<std::size_t>
34- {
35- constexpr static auto value = "std::size_t";
36- };
34+ constexpr static auto value = "std::size_t";
35+ };
3736
38- template<>
39- struct type_info<std::string>
40- {
41- constexpr static auto value = "std::string";
42- };
43- }
37+ template <>
38+ struct magic ::type_info< std::string >
39+ {
40+ constexpr static auto value = "std::string";
41+ };
4442
4543// use name_of to get the display name
4644constexpr auto name = magic::name_of<std::size_t >();
47- static_assert ( name == " std::size_t" );
45+ // name => "std::size_t"
4846
4947constexpr auto name2 = magic::name_of<std::string>();
50- static_assert (name2 == " std::string" );
48+ // name => "std::string"
5149```
5250
53- * visualize type
51+ - * visualize type*
5452``` cpp
5553// for some complex type, it is hard to understand for human
56- // we can visualize it to a more readable form
54+ // we can visualize it as a tree to make it more readable
5755
5856using T = int (*(*(*)(int *))[4 ])(int *); // hard to understand
5957std::cout << magic::full_tree_of<T>() << std::endl;
6058```
61- Output:
59+ * Output:*
6260
63- ![ ptr] ( docs/ptr .png )
61+ ![ ptr] ( docs/assets/sample_ptr .png )
6462
63+ ----------------
6564``` cpp
6665using T = std::map<int , std::string>;
6766std::cout << magic::full_tree_of<T>() << std::endl;
6867```
69- Output:
70-
71- ![ map] ( docs/map.png )
68+ * Output* :
69+ ![ map] ( docs/assets/sample_map.png )
7270
7371you can also use ` tree_of ` to get a more compact form, more details see [ type] ( docs/type.md ) .
7472
75- ### [ aggregate class] ( https://en.cppreference.com/w/cpp/language/aggregate_initialization#Definitions )
76- * just include ` magic/struct.h ` to use these features*
73+ ## [ aggregate class] ( https://en.cppreference.com/w/cpp/language/aggregate_initialization#Definitions )
74+ ** just include ` magic/struct.h ` to use these features* *
7775
7876``` cpp
7977struct Complex
@@ -83,56 +81,119 @@ struct Complex
8381}; // Complex is an aggregate class
8482```
8583
86- - Retrieve field count of an aggregate class
84+ - * retrieve field count of an aggregate class*
8785``` cpp
88- static_assert (magic::field_count_of<Complex>() == 2 );
86+ constexpr auto count = magic::field_count_of<Complex>();
87+ // count => 2
8988```
90- - Retrieve the field types for an aggregate class
89+ - * retrieve the field types for an aggregate class*
9190``` cpp
92- using T = magic::field_types_of<Complex>;
93- static_assert (std::same_as<T, std::tuple<std::string, std::vector<int >>>);
91+ using Types = magic::field_types_of<Complex>;
92+ // Types => std::tuple<std::string, std::vector<int>>
9493```
95- - Retrieve the field type at a given index for an aggregate class
94+ - * retrieve the field type at a given index for an aggregate class*
9695``` cpp
97- static_assert (std::same_as<magic::field_type_of<Complex, 0 >, std::string>);
98- static_assert (std::same_as<magic::field_type_of<Complex, 1 >, std::vector<int >>);
96+ using First = magic::field_type_of<Complex, 0 >;
97+ // First => std::string
98+
99+ using Second = magic::field_type_of<Complex, 1 >;
100+ // Second => std::vector<int>
99101```
100- - Retrieve the field names for an aggregate class
102+ - * retrieve the field names for an aggregate class*
101103``` cpp
102104constexpr auto names = magic::field_names_of<Complex>();
103- static_assert ( names == std::array<std::string_view, 2 > {"name", "vec"});
105+ // names => std::array{"name", "vec"}
104106```
105107
106- - Retrieve the field name at a given index for an aggregate class
108+ - * retrieve the field name at a given index for an aggregate class*
107109``` cpp
108- static_assert(magic::field_name_of<Complex>(0) == "name");
109- static_assert(magic::field_name_of<Complex>(1) == "vec");
110+ constexpr auto name1 = magic::field_name_of<Complex>(0 );
111+ // name1 => "name"
112+
113+ constexpr auto name2 = magic::field_name_of<Complex>(1 );
114+ // name2 => "vec"
110115```
111116
112- - Retrieve the field reference at a given index for an aggregate class
117+ - * retrieve the field reference at a given index for an aggregate class*
113118``` cpp
114119Complex c{"hello", {1, 2, 3}};
115- std::cout << magic::field_of<0>(c) << std::endl;
116- // output: hello
117120
118- std::cout << magic::field_of<1>(c)[ 1] << std::endl;
119- // output: 2
121+ auto& value = magic::field_of<0>(c);
122+ // value => "hello"
123+
124+ auto& value2 = magic::field_of<1>(c);
125+ // value2 => std::vector{1, 2, 3}
120126```
121127
122- - Traverse all fields of an aggregate class
128+ - *traverse all fields of an aggregate class*
123129```cpp
124- Complex c{"hello", {1, 2, 3}};
125130auto f = [](auto field)
126131{
132+ constexpr auto index = field.index();
133+ constexpr auto name = field.name();
134+ using type = decltype(field)::type;
135+ if constexpr (name == "name")
136+ {
137+ std::cout << "index: " << index
138+ << ", name: " << name
139+ << ", value: " << field.value() << std::endl;
140+ }
141+ else if constexpr (name == "vec")
142+ {
143+ std::cout << "index: " << index
144+ << ", name: " << name
145+ << ", value: " << field.value()[0] << std::endl;
146+ }
147+ };
127148
149+ magic::foreach (complex, f);
150+ // out =>
151+ // index: 0, name: name, value: hello
152+ // index: 1, name: vec, value: 1
153+ ```
154+ ## enum
155+ ** just include ` magic/enum.h ` to use these features**
156+ ``` cpp
157+ enum Color
158+ {
159+ RED,
160+ GREEN,
161+ BLUE
128162};
129- magic::foreach(c, f);
130163```
131- ### enum
132- - Retrieve the enum count
164+ - * retrieve the enum count*
165+ ``` cpp
166+ constexpr auto count = magic::enum_count_of<Color>();
167+ // count => 3
168+ ```
169+ - * retrieve the enum names*
170+ ``` cpp
171+ constexpr auto & names = magic::enum_names_of<Color>();
172+ // names => std::array{"RED", "GREEN", "BLUE"}
173+ ```
174+ - * retrieve the enum name*
175+ ``` cpp
176+ constexpr auto name = magic::name_of<Color::RED>();
177+ // name => "RED"
133178
134- - Retrieve the enum names
179+ Color color = Color::GREEN;
180+ auto name2 = magic::name_of(color);
181+ // name => "GREEN"
182+ ```
183+ - * retrieve the bit field enum value*
184+ ``` cpp
185+
186+
187+ ```
188+
189+ - * traverse all enum values*
190+ ``` cpp
191+
192+ ```
135193
136- - Retrieve the enum nam
194+ # Limitations
137195
138- - Retrieve the bit field enum value
196+ # Support
197+ - ` gcc ` > 12
198+ - ` clang ` > 15
199+ - ` msvc ` > 19.29
0 commit comments