Add member function implementation stubs using reflection - #168
Conversation
979e672 to
51dc367
Compare
c55ff80 to
9c390f3
Compare
88589f9 to
e80adf5
Compare
a6962a4 to
f0ded1c
Compare
f0ded1c to
553b460
Compare
b1fbb5d to
8dbc192
Compare
RyanJK5
left a comment
There was a problem hiding this comment.
Good work! The core of it seems to be functioning nicely :)
RyanJK5
left a comment
There was a problem hiding this comment.
Good progress, I tagged a few things that I missed in my initial review.
| template for (constexpr std::meta::info member : std::define_static_array( | ||
| std::define_static_array( | ||
| members_of(InterfaceType, | ||
| std::meta::access_context::unprivileged())) | | ||
| std::views::filter(std::meta::is_function) | | ||
| std::views::filter( | ||
| std::not_fn(std::meta::is_special_member_function)) | | ||
| std::views::filter( | ||
| std::not_fn(std::meta::is_static_member)) | | ||
| std::views::filter(std::meta::has_identifier))) { | ||
| member_base_types.push_back( | ||
| ^^typename member_base_generator<member>::member_base); | ||
| } |
There was a problem hiding this comment.
This approach is a bit less noisy and reduces some of the heavyweight template instantiations that come from template for (may not be perfect):
| template for (constexpr std::meta::info member : std::define_static_array( | |
| std::define_static_array( | |
| members_of(InterfaceType, | |
| std::meta::access_context::unprivileged())) | | |
| std::views::filter(std::meta::is_function) | | |
| std::views::filter( | |
| std::not_fn(std::meta::is_special_member_function)) | | |
| std::views::filter( | |
| std::not_fn(std::meta::is_static_member)) | | |
| std::views::filter(std::meta::has_identifier))) { | |
| member_base_types.push_back( | |
| ^^typename member_base_generator<member>::member_base); | |
| } | |
| for (std::meta::info member : members_of(InterfaceType, std::meta::access_context::unprivileged()) | | |
| std::views::filter(std::meta::is_function) | | |
| std::views::filter(std::not_fn(std::meta::is_special_member_function)) | | |
| std::views::filter(std::not_fn(std::meta::is_static_member)) | | |
| std::views::filter(std::meta::has_identifier)) { | |
| member_base_types.push_back(dealias(substitute(^^member_base_generator_t, {reflect_constant(member)}))); | |
| } |
It would require adding:
template <std::meta::info Member>
using member_base_generator_t = member_base_generator<Member>::member_base| TEST(ReflectionProtocolViewTest, NonConstMemberFunctionNotInvocableFromConst) { | ||
| struct Interface { | ||
| void update(int value); | ||
| }; | ||
|
|
||
| static_assert( | ||
| !std::is_invocable_v< | ||
| decltype((std::declval<const protocol_view<Interface>&>().update)), | ||
| int>); | ||
| } |
There was a problem hiding this comment.
Isn't this behavior incorrect? I thought protocol_view used shallow const, so a const protocol_view should be able to call update, whereas a protocol_view<const Interface> should not.
| consteval auto protocol_interface_functions_of() { | ||
| return std::define_static_array( | ||
| std::define_static_array( | ||
| members_of(Type, std::meta::access_context::unprivileged())) | | ||
| std::views::filter(std::meta::is_function) | | ||
| std::views::filter(std::not_fn(std::meta::is_static_member)) | | ||
| std::views::filter(std::meta::has_identifier)); | ||
| } |
There was a problem hiding this comment.
Since this is producing a static array anyway, I think it makes sense to make this a variable template. That way the results are cached if this is ever called again.
| consteval auto protocol_interface_functions_of() { | |
| return std::define_static_array( | |
| std::define_static_array( | |
| members_of(Type, std::meta::access_context::unprivileged())) | | |
| std::views::filter(std::meta::is_function) | | |
| std::views::filter(std::not_fn(std::meta::is_static_member)) | | |
| std::views::filter(std::meta::has_identifier)); | |
| } | |
| constexpr inline auto protocol_interface_functions_of = std::define_static_array( | |
| members_of(Type, std::meta::access_context::unprivileged()) | | |
| std::views::filter(std::meta::is_function) | | |
| std::views::filter(std::not_fn(std::meta::is_static_member)) | | |
| std::views::filter(std::meta::has_identifier)); |
NOTE: I also dropped the inner define_static_array, which I believe was unnecessary. Please add it back if I am mistaken.
|
|
||
| template <typename T> | ||
| class protocol_view { | ||
| class protocol_view : public detail::protocol_stubs_t<T> { |
There was a problem hiding this comment.
Related to my comment on the NonConstMemberFunctionNotInvocableFromConst test: I believe this is incorrect. protocol_view<I> should inherit from a slightly different version of protocol_stubs_t where every member function is const regardless of whether or not it was const in the interface. Later on, protocol_view<const I> would inherit from a protocol_stubs_t that filters out all of the non-const functions as well.
Adds stubs for member function to both
protocolandprotocol_view. Stub member functions cannot be called (there is currently no vtable to forward calls), but their signatures can be checked at compile-time.