Skip to content

Commit 3015d75

Browse files
Add MemberTypeOf & GetMemberAt & EnumerateMembers and make use of it
Signed-off-by: Christian Parpart <[email protected]>
1 parent 7b5ef42 commit 3015d75

File tree

2 files changed

+52
-29
lines changed

2 files changed

+52
-29
lines changed

include/reflection-cpp/reflection.hpp

Lines changed: 40 additions & 26 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,27 +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.
686698
template <typename Object, typename Callable>
687-
void CallOnMembers(Object const& object, Callable&& callable)
699+
constexpr void EnumerateMembers(Object& object, Callable&& callable)
688700
{
689-
template_for<0, Reflection::CountMembers<Object>>(
690-
[&]<auto I>() { callable(Reflection::MemberNameOf<I, Object>, std::get<I>(Reflection::ToTuple(object))); });
701+
template_for<0, CountMembers<Object>>([&]<auto I>() { callable.template operator()<I>(GetMemberAt<I>(object)); });
691702
}
692703

704+
/// Calls a callable on each member of an object with the index and member's type as template arguments.
693705
template <typename Object, typename Callable>
694-
void CallOnMembers(Object& object, Callable&& callable)
706+
constexpr void EnumerateMembers(Callable&& callable)
695707
{
696-
template_for<0, Reflection::CountMembers<Object>>(
697-
[&]<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
698715
}
699716

700-
/// Calls a callable on each member of an object with the index of the member as the first argument.
701-
/// and the member's default-constructed value as the second argument.
702717
template <typename Object, typename Callable>
703-
void CallOnMembersWithIndex(Object& object, Callable&& callable)
718+
void CallOnMembers(Object& object, Callable&& callable)
704719
{
705-
template_for<0, Reflection::CountMembers<Object>>(
706-
[&]<auto I>() { callable(I, std::get<I>(Reflection::ToTuple(object))); });
720+
EnumerateMembers<Object>(object,
721+
[&]<size_t I, typename T>(T&& value) { callable(MemberNameOf<I, Object>, value); });
707722
}
708723

709724
/// Folds over the members of a type without an object of it.
@@ -718,11 +733,9 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab
718733
{
719734
// clang-format off
720735
ResultType result = initialValue;
721-
template_for<0, Reflection::CountMembers<Object>>(
722-
[&]<size_t I>() {
723-
result = callable(Reflection::MemberNameOf<I, Object>,
724-
std::get<I>(Reflection::ToTuple(Object {})),
725-
result);
736+
EnumerateMembers<Object>(
737+
[&]<size_t I, typename MemberType>() {
738+
result = callable.template operator()<I, MemberTypeOf<I, Object>>(result);
726739
}
727740
);
728741
// clang-format on
@@ -738,15 +751,16 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab
738751
///
739752
/// @return The result of the fold
740753
template <typename Object, typename Callable, typename ResultType>
741-
constexpr ResultType FoldMembers(Object const& object, ResultType initialValue, Callable const& callable)
754+
constexpr ResultType FoldMembers(Object& object, ResultType initialValue, Callable const& callable)
742755
{
743756
// clang-format off
744757
ResultType result = initialValue;
745-
template_for<0, Reflection::CountMembers<Object>>([&]<size_t I>() {
746-
result = callable(Reflection::MemberNameOf<I, Object>,
747-
std::get<I>(Reflection::ToTuple(object)),
748-
result);
749-
});
758+
EnumerateMembers<Object>(
759+
object,
760+
[&]<size_t I, typename MemberType>(MemberType&& value) {
761+
result = callable(MemberNameOf<I, Object>, value, result);
762+
}
763+
);
750764
return result;
751765
// clang-format on
752766
}

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)