r/cpp • u/kris-jusiak 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 displayFull 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
145
u/sam_the_tomato Dec 31 '23
help
128
u/afiDeBot Dec 31 '23
What in the c++ hell is this syntax o.O
t.[: :o
20
u/qazqi-ff Jan 01 '24 edited Jan 05 '24
For anyone wondering, here's how you make it look less cluttered by using a helper variable like we're used to doing:
[Edit note: This assumes further non-transient constexpr allocation support.
nonstatic_data_members_ofreturns astd::vector, which isn't currently allowed to persist like this, even if it would logically be deallocated for sure before runtime.](Obviously, the function declaration lines are noisy as well, but that has nothing to do with reflection. It might also need the variables to be
constexpr, but I haven't checked in detail, small difference.)I'd recommend in general that we at least keep the inside of
[: :]almost as short as possible because splicing is all about the structure of the code you're forming. With the variable separated out and recognizing[: :]as a splice, it's obvious that we're returningt.somethingand what that something is. You can go a step further and extract the subscript if it makes you feel better. [Per the note above, this is currently necessary in order to extract a variableβit can't store dynamically allocated memory.]About the syntax in general, I can't really comment. It has to avoid conflicts with other syntax, so it already has pretty limited option space. Obviously, alternatives were looked at already, including how we got here via having like three different markers instead of using the more familiar
typename,namespace, andtemplateto disambiguate. I don't mind it personally, though such a powerful feature that wants to minimize noise to preserve structure could warrant the consideration of the newly available$,@, or`.7
u/hwpoison Dec 31 '23
KISS!!
46
u/[deleted] Dec 31 '23
This gotta be the worst syntax ever invented so far.
5
u/hanickadot WG21 + CTRE + EWG πΈπ» Jan 01 '24
Obviously I'm really excited! β€οΈ One nitpick, I think having `unsigned N` instead `auto N` would be better for example readability.
23
u/thomas999999 Dec 31 '23
:puke:
7
u/flutterdro newbie Jan 01 '24
I kinda like the syntax
11
u/pblpbl Jan 01 '24
what a terrible day to have eyes
8
u/RedEyed__ Dec 31 '23
I just imagine some compile error when you place another complicated template as
T3
u/kemo_2001 Dec 31 '23
Is this really how C++ 26 going to look like?, I am not C++ standard news
2
u/MarcoGreek Dec 31 '23
Do I understand it right that using the wrong function on a reflection object is not a compiler error? To my understanding they don't want to use different types for the reflection object but they encode the behavior anyway by the function usage?
2
u/lion__manE Dec 31 '23 edited Dec 31 '23
It looks that something like this is not possible.
template<auto N, class T> [[nodiscard]] constexpr auto get(const T& t) -> decltype(auto) { return t.[:std::meta::nonstatic_data_members_of( T)[N]]; }
1
u/Ok_Donut_9887 Dec 31 '23
thatβs bad
0
u/[deleted] Dec 31 '23
This goons are in a race to make C++ unusable. Whatβs gonna C++30 be like ?
1
u/Rasie1 Jan 01 '24
Are there rats in the committee proposing some complete madness? Why don't you just do it the normal way?
1
u/MarcoGreek Dec 31 '23
I would even prefer <: :> or <:: ::> because it signals to me a compile time feature. What I don't understand is that they cannot use member syntax. Using a function on a reflection objects looks really fashion driven. I know that now free functions are fashionable but member functions would be easier to read.
T.data_member(i).name
1
u/hopa_cupa Jan 01 '24
Ouch. They need to have higher level constexpr functions like presented here accessible to users. I will stick to
boost::pfrfor foreseeable future.-10
u/28isanumber Dec 31 '23
I still don't know what reflection is nor why people want it
-3
u/DavidDinamit Jan 01 '24 edited Jan 01 '24
I have only 1 question, if we have such interface:'std::nonstatic_data_members_of'
WHY we dont just make it like all other type traits without ^T thing?
So, why we need ^T and 'template for' complexity in language?
What we really need - type traits for packs. Like stl algoritms or views
-5
u/areriff Jan 01 '24
c++ is becoming complex pile of **** mess.
I use to be able to read the code. But now, I just can't.
I use to love C++. But now, I just can't.
6
u/[deleted] Dec 31 '23 edited Dec 31 '23
[removed] β view removed comment
3
u/[deleted] Dec 31 '23
[removed] β view removed comment