After an introduction to reflection and a basic introduction to metafunctions in C++26, this time it’s about enums and classes.
Advertisement
Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages C++, Python, and Haskell, but also frequently speaks at expert conferences. On his blog Modern C++ he discusses his passion C++ in depth.
The names of metafunctions for accessing elements of an enum or class are often the same.
Access elements of an enum
The following program is based on a program by David VandeWorde. David is one of the fathers of reflection in C++ and included this example in his presentation.Reflections on C++ Reflection used.
The program loops through an enum and displays the name and value for each enumerator.
// daveed.cpp
#include
#include
#include
template
struct enum_item {
std::string_view name;
E value;
};
template
consteval auto get_enum_data() {
std::array, std::meta::enumerators_of(^E).size()> result;
int k = 0;
for (auto mem: std::meta::enumerators_of(^E))
result(k++) = enum_item{ std::meta::identifier_of(mem), std::meta::extract(mem) };
return result;
}
enum MyEnum {
x,
y,
e = -1,
z = 99
};
int main() {
std::cout << '\n';
std::cout << "members of " << std::meta::identifier_of(^MyEnum) << '\n';
for (auto x: get_enum_data()) {
std::cout << " " << x.name << " = " << (long)x.value << '\n';
}
std::cout << '\n';
}
The code snippet provided demonstrates the use of experimental metaprogramming features in C++ to check and manipulate enum types at compile time. The code starts by inserting the necessary headers:array
>For array support,experimental
,meta
> for metaprogramming utilities andiostream
>For input-output operations.
enum_item
Structure template is defined to hold information about an enum element. It consists of two elements: name
is one std::string_view
which represents the name of the enum element, and value
which is the value of the enum element of data type E
prevent.
get_enum_data
The function template is like this consteval
Marked, which means it will be evaluated at compile time. This function produces an array enum_item
-Structures for a specific enum type E
she uses it std::meta::enumerators_of
The function of getting enum elements of enum type and iterating through them. For each enum value it creates one enum_item
with the name and value of the enum value, where they std::meta::identifier_of
got the name, and std::meta::extract
To get the value. The resulting array is then returned.
MyEnum
-The enum is defined with four enum elements: y
, x
, e
(explicitly set to -1) and z
(explicitly set to 99). This computation is used as an example to demonstrate metaprogramming features.
In main
The function, code first outputs a new line for formatting purposes. then enum type name MyEnum
with the help of std::meta::identifier_of
Were issued. will be next get_enum_data()
called into the table of enum_item-
Structures for MyEnum
And iterate through this array. for all enum_item
The name and value of the enum element are output. Values are stored for consistent output formatting long
Converted. Finally, there is output for another line break formatting.
Overall, this code shows how reflection can be used at compile time to check enum types and generate useful metadata such as enum names and values, which can then be used at run time.
Here is the output of the program:
my little experiment
This explanation was created using AI tools co-pilot Created by Microsoft. I have to admit that I was quite impressed since the feature described is fairly new.
Access elements of a class
The following program shows two ways to access elements of a class: by index and by name.
// reflectionClass.cpp
#include
#include
struct Base {
int i{};
void inc(int& j){ j++; }
};
consteval auto number(int n) {
//return std::meta::nonstatic_data_members_of(^Base)(n);
return std::meta::members_of(^Base)(n);
}
consteval auto named(std::string_view name) {
for (std::meta::info field : std::meta::members_of(^Base)) {
if (std::meta::has_identifier(field) && std::meta::identifier_of(field) == name)
return field;
}
return std::meta::info{};
}
int main() {
std::cout << '\n';
Base base;
base.(:number(0):) = 1;
std::cout << "base.i= " << base.i << '\n';
base.(:number(1):)(base.i);
std::cout << "base.i= " << base.i << '\n';
std::cout << '\n';
base.(:named("i"):) = 3;
std::cout << "base.i= " << base.i << '\n';
base.(:named("inc"):)(base.i);
std::cout << "base.i= " << base.i << '\n';
}
Base
This is the class I want to think about. metafunctionnumber
” And “named
“Provide me with the information I need.
"number": std::meta::members_of(^Base)(n)
returns elementn
FromBase
Back. On the contrary, there is “number": std::meta::nonstatic_data_members_of(^Base)(n)
non-static data elementsn
FromBase
Back. The Reflection library also has a meta function that can be used to retrieve all the static data members of a class:std::meta::static_data_members_of(^Base)(n)
namend
:iterates through all elements ofBase
and returns the element with namename
Back:std::meta::identifier_of(field) == name
Now I will go to the main event. Element i
From Base
Increases. either by assigning a value or calling a function inc
Using the wrong index or name will cause a compile-time error.:(:member_number(10):) = 1).
Finally, I show the output of the program here:
What will happen next?
In my next article I will continue playing with reflection in C++26.
(rme)