Skip to content

Commit 788bb64

Browse files
Merge pull request #12 from contour-terminal/feature/CallOnMembers-with-index
Add CallOnMembers-variant, MemberTypeOf & GetMemberAt & EnumerateMembers API
2 parents b93b641 + 3015d75 commit 788bb64

File tree

2 files changed

+55
-23
lines changed

2 files changed

+55
-23
lines changed

include/reflection-cpp/reflection.hpp

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -456,17 +456,27 @@ inline constexpr decltype(auto) ToTuple(T&& t) noexcept
456456
// clang-format on
457457
}
458458

459+
template <auto I, typename T>
460+
constexpr decltype(auto) GetMemberAt(T&& t)
461+
{
462+
return std::get<I>(ToTuple(std::forward<T>(t)));
463+
}
464+
465+
/// Represents the type of the member at index I of type Object
466+
template <auto I, typename Object>
467+
using MemberTypeOf = std::remove_cvref_t<decltype(std::get<I>(ToTuple(Object {})))>;
468+
459469
template <class T>
460470
struct WrappedPointer final
461471
{
462-
const T* ptr;
472+
T* pointer;
463473
};
464474

465475
template <size_t N, class T>
466476
constexpr auto GetElementPtrAt(T&& t) noexcept
467477
{
468-
auto& p = get<N>(ToTuple(t));
469-
return WrappedPointer<std::remove_cvref_t<decltype(p)>> { &p };
478+
auto& p = GetMemberAt<N>(std::forward<T>(t));
479+
return WrappedPointer<std::remove_reference_t<decltype(p)>> { &p };
470480
}
471481

472482
namespace detail
@@ -673,7 +683,7 @@ consteval auto GetName()
673683
std::string_view str = REFLECTION_PRETTY_FUNCTION;
674684
str = str.substr(str.rfind("::") + 2);
675685
str = str.substr(0, str.find('>'));
676-
return str.substr(str.find('<')+1);
686+
return str.substr(str.find('<') + 1);
677687
#else
678688
constexpr auto MarkerStart = std::string_view { "E = " };
679689
std::string_view str = REFLECTION_PRETTY_FUNCTION;
@@ -683,18 +693,32 @@ consteval auto GetName()
683693
#endif
684694
}
685695

696+
/// Calls a callable on each member of an object with the index of the member as the first argument.
697+
/// and the member's default-constructed value as the second argument.
698+
template <typename Object, typename Callable>
699+
constexpr void EnumerateMembers(Object& object, Callable&& callable)
700+
{
701+
template_for<0, CountMembers<Object>>([&]<auto I>() { callable.template operator()<I>(GetMemberAt<I>(object)); });
702+
}
703+
704+
/// Calls a callable on each member of an object with the index and member's type as template arguments.
686705
template <typename Object, typename Callable>
687-
void CallOnMembers(Object const& object, Callable&& callable)
706+
constexpr void EnumerateMembers(Callable&& callable)
688707
{
689-
template_for<0, Reflection::CountMembers<Object>>(
690-
[&]<auto I>() { callable(Reflection::MemberNameOf<I, Object>, std::get<I>(Reflection::ToTuple(object))); });
708+
// clang-format off
709+
template_for<0, CountMembers<Object>>(
710+
[&]<auto I>() {
711+
callable.template operator()<I, MemberTypeOf<I, Object>>();
712+
}
713+
);
714+
// clang-format on
691715
}
692716

693717
template <typename Object, typename Callable>
694718
void CallOnMembers(Object& object, Callable&& callable)
695719
{
696-
template_for<0, Reflection::CountMembers<Object>>(
697-
[&]<auto I>() { callable(Reflection::MemberNameOf<I, Object>, std::get<I>(Reflection::ToTuple(object))); });
720+
EnumerateMembers<Object>(object,
721+
[&]<size_t I, typename T>(T&& value) { callable(MemberNameOf<I, Object>, value); });
698722
}
699723

700724
/// Folds over the members of a type without an object of it.
@@ -709,11 +733,9 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab
709733
{
710734
// clang-format off
711735
ResultType result = initialValue;
712-
template_for<0, Reflection::CountMembers<Object>>(
713-
[&]<size_t I>() {
714-
result = callable(Reflection::MemberNameOf<I, Object>,
715-
std::get<I>(Reflection::ToTuple(Object {})),
716-
result);
736+
EnumerateMembers<Object>(
737+
[&]<size_t I, typename MemberType>() {
738+
result = callable.template operator()<I, MemberTypeOf<I, Object>>(result);
717739
}
718740
);
719741
// clang-format on
@@ -729,15 +751,16 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab
729751
///
730752
/// @return The result of the fold
731753
template <typename Object, typename Callable, typename ResultType>
732-
constexpr ResultType FoldMembers(Object const& object, ResultType initialValue, Callable const& callable)
754+
constexpr ResultType FoldMembers(Object& object, ResultType initialValue, Callable const& callable)
733755
{
734756
// clang-format off
735757
ResultType result = initialValue;
736-
template_for<0, Reflection::CountMembers<Object>>([&]<size_t I>() {
737-
result = callable(Reflection::MemberNameOf<I, Object>,
738-
std::get<I>(Reflection::ToTuple(object)),
739-
result);
740-
});
758+
EnumerateMembers<Object>(
759+
object,
760+
[&]<size_t I, typename MemberType>(MemberType&& value) {
761+
result = callable(MemberNameOf<I, Object>, value, result);
762+
}
763+
);
741764
return result;
742765
// clang-format on
743766
}

test-reflection-cpp.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ TEST_CASE("nested", "[reflection]")
7171
TEST_CASE("FoldMembers.type", "[reflection]")
7272
{
7373
// clang-format off
74-
auto const result = Reflection::FoldMembers<TestStruct>(0, [](auto&& /*name*/, auto&& /*value*/, auto&& result) {
75-
return result + 1;
74+
auto const result = Reflection::FoldMembers<TestStruct>(size_t{0}, []<size_t I, typename T>(auto&& result) {
75+
return result + I;
7676
});
7777
// clang-format on
78-
CHECK(result == 5);
78+
CHECK(result == 0 + 0 + 1 + 2 + 3 + 4);
7979
}
8080

8181
struct S
@@ -93,3 +93,12 @@ TEST_CASE("FoldMembers.value", "[reflection]")
9393

9494
CHECK(result == 6);
9595
}
96+
97+
TEST_CASE("MemberTypeOf", "[reflection]")
98+
{
99+
static_assert(std::same_as<Reflection::MemberTypeOf<0, TestStruct>, int>);
100+
static_assert(std::same_as<Reflection::MemberTypeOf<1, TestStruct>, float>);
101+
static_assert(std::same_as<Reflection::MemberTypeOf<2, TestStruct>, double>);
102+
static_assert(std::same_as<Reflection::MemberTypeOf<3, TestStruct>, std::string>);
103+
static_assert(std::same_as<Reflection::MemberTypeOf<4, TestStruct>, Person>);
104+
}

0 commit comments

Comments
 (0)