Skip to content

Commit 477cfbd

Browse files
Merge pull request #21 from contour-terminal/features/iterate_over_sequence
Allow iteration over sequence in EnumerateMembers
2 parents b51d326 + b26409b commit 477cfbd

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

include/reflection-cpp/reflection.hpp

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,11 @@ namespace detail
604604
template <typename... Ts, typename F>
605605
constexpr void enumerate_types(F&& f)
606606
{
607-
[&f]<auto... Is>(std::index_sequence<Is...>) {
607+
[&f]<auto... Is>(std::index_sequence<Is...>)
608+
{
608609
(f.template operator()<Ts, Is>(), ...);
609-
}(std::index_sequence_for<Ts...> {});
610+
}
611+
(std::index_sequence_for<Ts...> {});
610612
}
611613

612614
template <auto... Xs, typename F>
@@ -625,9 +627,22 @@ constexpr void template_for(F&& f)
625627
{
626628
using t = std::common_type_t<decltype(B), decltype(E)>;
627629

628-
[&f]<auto... Xs>(std::integer_sequence<t, Xs...>) {
630+
[&f]<auto... Xs>(std::integer_sequence<t, Xs...>)
631+
{
629632
detail::for_values<(B + Xs)...>(f);
630-
}(std::make_integer_sequence<t, E - B> {});
633+
}
634+
(std::make_integer_sequence<t, E - B> {});
635+
}
636+
637+
template <typename ElementMask, typename F>
638+
constexpr void template_for(F&& f)
639+
{
640+
using t = typename ElementMask::value_type;
641+
[&f]<auto... Xs>(std::integer_sequence<t, Xs...>)
642+
{
643+
Reflection::detail::for_values<(Xs)...>(f);
644+
}
645+
(ElementMask {});
631646
}
632647

633648
template <auto P>
@@ -674,6 +689,22 @@ consteval auto GetName()
674689
#endif
675690
}
676691

692+
/// Calls a callable on members of an object specified with ElementMask sequence with the index of the member as the
693+
/// first argument. and the member's default-constructed value as the second argument.
694+
template <typename ElementMask, typename Object, typename Callable>
695+
constexpr void EnumerateMembers(Object& object, Callable&& callable)
696+
{
697+
template_for<ElementMask>([&]<auto I>() { callable.template operator()<I>(GetMemberAt<I>(object)); });
698+
}
699+
700+
/// Calls a callable on members of an object specified with ElementMask sequence with the index and member's type as
701+
/// template arguments.
702+
template <typename ElementMask, typename Object, typename Callable>
703+
constexpr void EnumerateMembers(Callable&& callable)
704+
{
705+
template_for<ElementMask>([&]<auto I>() { callable.template operator()<I, MemberTypeOf<I, Object>>(); });
706+
}
707+
677708
/// Calls a callable on each member of an object with the index of the member as the first argument.
678709
/// and the member's default-constructed value as the second argument.
679710
template <typename Object, typename Callable>
@@ -688,7 +719,7 @@ constexpr void EnumerateMembers(Callable&& callable)
688719
{
689720
// clang-format off
690721
template_for<0, CountMembers<Object>>(
691-
[&]<auto I>() {
722+
[&]<auto I>() {
692723
callable.template operator()<I, MemberTypeOf<I, Object>>();
693724
}
694725
);
@@ -699,7 +730,7 @@ template <typename Object, typename Callable>
699730
requires std::same_as<void, std::invoke_result_t<Callable, std::string, MemberTypeOf<0, Object>>>
700731
void CallOnMembers(Object& object, Callable&& callable)
701732
{
702-
EnumerateMembers<Object>(object,
733+
EnumerateMembers(object,
703734
[&]<size_t I, typename T>(T&& value) { callable(MemberNameOf<I, Object>, value); });
704735
}
705736

@@ -738,7 +769,7 @@ constexpr ResultType FoldMembers(Object& object, ResultType initialValue, Callab
738769
{
739770
// clang-format off
740771
ResultType result = initialValue;
741-
EnumerateMembers<Object>(
772+
EnumerateMembers(
742773
object,
743774
[&]<size_t I, typename MemberType>(MemberType&& value) {
744775
result = callable(MemberNameOf<I, Object>, value, result);

test-reflection-cpp.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <string>
77
#include <string_view>
8+
#include <utility>
89

910
struct Person
1011
{
@@ -136,6 +137,25 @@ TEST_CASE("EnumerateMembers.index_and_type", "[reflection]")
136137
});
137138
}
138139

140+
TEST_CASE("EnumerateMembers.partial", "[reflection]")
141+
{
142+
Reflection::EnumerateMembers<std::integer_sequence<size_t, 0, 2>, Person>([]<auto I, typename T>() {
143+
if constexpr (I == 0)
144+
{
145+
static_assert(std::same_as<T, std::string_view>);
146+
}
147+
if constexpr (I == 1)
148+
{
149+
static_assert(false);
150+
}
151+
if constexpr (I == 2)
152+
{
153+
static_assert(std::same_as<T, int>);
154+
}
155+
});
156+
}
157+
158+
139159
TEST_CASE("CallOnMembers", "[reflection]")
140160
{
141161
auto ps = Person { .name = "John Doe", .email = "john@doe.com", .age = 42 };
@@ -247,3 +267,10 @@ TEST_CASE("Compare.nested", "[reflection]")
247267
Reflection::CollectDifferences(t1, t3, differenceCallback);
248268
CHECK(diff == "id: 2 != 3\n");
249269
}
270+
271+
TEST_CASE("TemplateFor over sequence", "[refleciton]")
272+
{
273+
std::string result {};
274+
Reflection::template_for<std::integer_sequence<size_t, 3, 2, 1>>([&]<size_t I>(){result += std::to_string(I);});
275+
CHECK(result == "321");
276+
}

0 commit comments

Comments
 (0)