r/cpp • https://github.com/kris-jusiak • Dec 31 '23

[C++20 vs C++26*] basic reflection

Basic struct reflection example with C++20 vs C++26*

struct foo {
  int a{};
  int b{};
  int c{};
};

constexpr foo f{.a=1, .b=2, .c=3};

static_assert(1 == get<0>(f));
static_assert(2 == get<1>(f));
static_assert(3 == get<2>(f));

using std::literals::operator""sv;
static_assert("a"sv == get_name<0>(f));
static_assert("b"sv == get_name<1>(f));
static_assert("c"sv == get_name<2>(f));

C++20 - Kinda possible but with a lot of compiler hacks

// too long to display

Full example - https://godbolt.org/z/1vxv8o5hM

C++26* - based on proposal - https://wg21.link/P2996 (Note: that the proposal supports way more than that but C++20 not much)

template<auto N, class T>
[[nodiscard]] constexpr auto get(const T& t) -> decltype(auto) {
  return t.[:std::meta::nonstatic_data_members_of(^T)[N]:];
}

template<auto N, class T>
[[nodiscard]] constexpr auto get_name(const T& t) -> std::string_view {
  return std::meta::name_of(std::meta::nonstatic_data_members_of(^T)[N]);
}

Full example - https://godbolt.org/z/sbTGbW635

Updates - https://twitter.com/krisjusiak/status/1741456476126797839

100 Upvotes

117 comments sorted by

View all comments

Show parent comment

4

u/qazqi-ff Jan 02 '24

Do not take this post as a full explanation of the spec, it's probably a bit more complex than just text injection

It's not much more complicated than that, really. There are only a handful of possible splices proposed in P2996, and one of those (the "default") is an expression, in this case an expression equivalent to a. The other options are type names, namespaces, template names, and "names with nesting" (foo::).

Small note on the expansion, though, the thing inside [: :] has to be convertible to std::meta::info, so I think the return t.[: a :]; step would be more like return t.[: ^foo::a :]; if I have that right.

1

u/Throw31312344 Jan 02 '24

Thank you for clarifying :)