Skip to content

Commit

Permalink
[reflection] Add customization for_each_field() directly
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkaratarakis committed Dec 10, 2024
1 parent 36438b2 commit 29e7181
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 5 deletions.
22 changes: 17 additions & 5 deletions include/fixed_containers/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,21 @@ template <typename T>
inline constexpr auto FIELD_NAMES = fixed_containers::reflection_detail::field_names_of_impl<
fixed_containers::reflection_detail::field_count_of_impl(std::decay_t<T>{})>(std::decay_t<T>{});

template <typename T>
struct ReflectionHelper
{
template <typename T2, typename Func>
static constexpr void for_each_field(T2&& instance, Func&& func)
{
auto tuple_view =
tuples::as_tuple_view<FIELD_NAMES<std::decay_t<T2>>.size()>(std::forward<T2>(instance));
tuples::for_each_entry(
tuple_view,
[&func]<typename Field>(std::size_t index, Field&& field)
{ func(FIELD_NAMES<std::decay_t<T2>>.at(index), std::forward<Field>(field)); });
}
};

} // namespace fixed_containers::reflection::customize

namespace fixed_containers::reflection
Expand All @@ -244,11 +259,8 @@ template <typename T, typename Func>
requires(Reflectable<std::decay_t<T>>)
constexpr void for_each_field(T&& instance, Func&& func)
{
constexpr const auto& FIELD_NAMES = field_names_of<T>();
auto tuple_view = tuples::as_tuple_view<FIELD_NAMES.size()>(instance);
tuples::for_each_entry(tuple_view,
[&func]<typename Field>(std::size_t index, Field&& field)
{ func(FIELD_NAMES.at(index), std::forward<Field>(field)); });
fixed_containers::reflection::customize::ReflectionHelper<std::decay_t<T>>::for_each_field(
std::forward<T>(instance), std::forward<Func>(func));
}

} // namespace fixed_containers::reflection
35 changes: 35 additions & 0 deletions test/reflection_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,41 @@ inline constexpr auto fixed_containers::reflection::customize::FIELD_NAMES<MyCus
"c",
});

template <>
struct fixed_containers::reflection::customize::ReflectionHelper<MyCustomStruct>
{
template <typename T2, typename Func>
requires std::same_as<std::decay_t<T2>, MyCustomStruct>
static constexpr void for_each_field(T2&& instance, Func&& func)
{
// Apply it twice for unit testing purposes
func(FIELD_NAMES<MyCustomStruct>.at(0), instance.a);
func(FIELD_NAMES<MyCustomStruct>.at(1), instance.b);
func(FIELD_NAMES<MyCustomStruct>.at(2), instance.c);

func(FIELD_NAMES<MyCustomStruct>.at(0), instance.a);
func(FIELD_NAMES<MyCustomStruct>.at(1), instance.b);
func(FIELD_NAMES<MyCustomStruct>.at(2), instance.c);
}
};

static_assert(fixed_containers::reflection::field_names_of<MyCustomStruct>().size() == 3);

namespace fixed_containers
{

TEST(Reflection, Customization)
{
constexpr auto RESULT = []()
{
MyCustomStruct instance{};
std::size_t counter = 0;
reflection::for_each_field(
instance, [&]<typename T>(const std::string_view& /*name*/, const T&) { counter++; });
return counter;
}();

static_assert(6 == RESULT);
}
} // namespace fixed_containers
#endif

0 comments on commit 29e7181

Please sign in to comment.