qlibs / reflect

C++20 Static Reflection library
306 stars 17 forks source link

Feature: Support for user defined constructors #50

Open SpintroniK opened 6 months ago

SpintroniK commented 6 months ago

I've been using this library, and I think it's fantastic. Well done! It looks like things started when this was posted: [C++20] 60 LOC constexpr get_name for members / no ifdefs / clang,gcc,msvc . I've been playing a bit with this example and realized it's possible to get structs name even if a user defined constructor exists. It's also possible to iterate over the members of a struct that has a user defined constructor. So far, getting names and values of a struct's members works if a user defined constructor exists. Of course, it only works if:

Do you think that's something that could be added to reflect to make it work on structs that have user defined constructors?

kris-jusiak commented 6 months ago

Thanks @SpintroniK.

Interesting, thanks for sharing. As far I understand, this is actually deducing the constructor parameters not the members, it just happen that in this examples constructor parameter match the public members. That would break if the constructor had different types as they wouldn't match members, right? I also think that not all constructors needed to be defined, you can just try to find the longest one up to sizesof(struct) or something. For the constructor parameters, there is also a way to deduce the - https://godbolt.org/z/3faKq5x3q.

So I think constructor traits would be a great addition, though not sure about relying on the fact that constructor matches member parameters unless I'm missing something? We would need to be able to somehow guarantee constructors and members are matching? Interested to hear thoughts regarding the approach/concerns?

SpintroniK commented 6 months ago

Very interesting, I like the constructor_traits! Not sure why I needed a default constructor, I think it was related to counting the members of the struct. I need to test that again, but apparently it's not strictly required, so I guess the constructor_traits is the way to go. You're right about not matching the members: https://godbolt.org/z/hM91zzxYM. The only thing that seem to be very important is the number of arguments of the constructor.

kris-jusiak commented 6 months ago

Thanks for following-up. It's very interesting how it actually works. Will add constructor traits to reflect.

SpintroniK commented 6 months ago

That would be very nice! I've been wanting to reflect on structs with constructors for a while. Been playing a little bit with the code you shared. This is what I came up with: https://godbolt.org/z/3s14PEv7K with the help of this post Counting the number of fields in an aggregate in C++20.

I didn't keep the code I wrote yesterday, but I think I had to add a default constructor when working with reflect. At first I didn't and got a compile error, not sure why though...

kris-jusiak commented 2 months ago

Just an update - https://github.com/qlibs/di supports constructor deduction and injection; there is ctor_traits which can accomplish that )by default it returns the constructor with the longest number of parameters but potentially it can be a list of all available candidates, it supports value categories too).

Example - https://godbolt.org/z/e98M6eq3q

struct Point
{
  Point() {}
  Point(int x_, int y_, int z_) : x{x_}, y{y_}, z{z_} {}
  Point(int x_, int y_) : x{x_}, y{y_}, z{0} {}
  int x;
  int y;
  int z;
};

template<class...> struct show_type;

int main() {
   show_type<di::ctor_traits<Point>::type>{}; // show_type<di::type_list<int, int, int>>
}
SpintroniK commented 2 months ago

That's pretty cool. The constructor with the longest number of parameters seems like a good default. Any chance to have that integrated into reflect to allow reflection on aggregates with constructors?

kris-jusiak commented 2 months ago

Yeah, let's add it inot reflect