diff --git a/include/reflection-cpp/reflection.hpp b/include/reflection-cpp/reflection.hpp index 9796325..6229d85 100644 --- a/include/reflection-cpp/reflection.hpp +++ b/include/reflection-cpp/reflection.hpp @@ -456,17 +456,27 @@ inline constexpr decltype(auto) ToTuple(T&& t) noexcept // clang-format on } +template +constexpr decltype(auto) GetMemberAt(T&& t) +{ + return std::get(ToTuple(std::forward(t))); +} + +/// Represents the type of the member at index I of type Object +template +using MemberTypeOf = std::remove_cvref_t(ToTuple(Object {})))>; + template struct WrappedPointer final { - const T* ptr; + T* pointer; }; template constexpr auto GetElementPtrAt(T&& t) noexcept { - auto& p = get(ToTuple(t)); - return WrappedPointer> { &p }; + auto& p = GetMemberAt(std::forward(t)); + return WrappedPointer> { &p }; } namespace detail @@ -673,7 +683,7 @@ consteval auto GetName() std::string_view str = REFLECTION_PRETTY_FUNCTION; str = str.substr(str.rfind("::") + 2); str = str.substr(0, str.find('>')); - return str.substr(str.find('<')+1); + return str.substr(str.find('<') + 1); #else constexpr auto MarkerStart = std::string_view { "E = " }; std::string_view str = REFLECTION_PRETTY_FUNCTION; @@ -683,18 +693,32 @@ consteval auto GetName() #endif } +/// Calls a callable on each member of an object with the index of the member as the first argument. +/// and the member's default-constructed value as the second argument. +template +constexpr void EnumerateMembers(Object& object, Callable&& callable) +{ + template_for<0, CountMembers>([&]() { callable.template operator()(GetMemberAt(object)); }); +} + +/// Calls a callable on each member of an object with the index and member's type as template arguments. template -void CallOnMembers(Object const& object, Callable&& callable) +constexpr void EnumerateMembers(Callable&& callable) { - template_for<0, Reflection::CountMembers>( - [&]() { callable(Reflection::MemberNameOf, std::get(Reflection::ToTuple(object))); }); + // clang-format off + template_for<0, CountMembers>( + [&]() { + callable.template operator()>(); + } + ); + // clang-format on } template void CallOnMembers(Object& object, Callable&& callable) { - template_for<0, Reflection::CountMembers>( - [&]() { callable(Reflection::MemberNameOf, std::get(Reflection::ToTuple(object))); }); + EnumerateMembers(object, + [&](T&& value) { callable(MemberNameOf, value); }); } /// Folds over the members of a type without an object of it. @@ -709,11 +733,9 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab { // clang-format off ResultType result = initialValue; - template_for<0, Reflection::CountMembers>( - [&]() { - result = callable(Reflection::MemberNameOf, - std::get(Reflection::ToTuple(Object {})), - result); + EnumerateMembers( + [&]() { + result = callable.template operator()>(result); } ); // clang-format on @@ -729,15 +751,16 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab /// /// @return The result of the fold template -constexpr ResultType FoldMembers(Object const& object, ResultType initialValue, Callable const& callable) +constexpr ResultType FoldMembers(Object& object, ResultType initialValue, Callable const& callable) { // clang-format off ResultType result = initialValue; - template_for<0, Reflection::CountMembers>([&]() { - result = callable(Reflection::MemberNameOf, - std::get(Reflection::ToTuple(object)), - result); - }); + EnumerateMembers( + object, + [&](MemberType&& value) { + result = callable(MemberNameOf, value, result); + } + ); return result; // clang-format on } diff --git a/test-reflection-cpp.cpp b/test-reflection-cpp.cpp index 236cde5..d4c98fc 100644 --- a/test-reflection-cpp.cpp +++ b/test-reflection-cpp.cpp @@ -71,11 +71,11 @@ TEST_CASE("nested", "[reflection]") TEST_CASE("FoldMembers.type", "[reflection]") { // clang-format off - auto const result = Reflection::FoldMembers(0, [](auto&& /*name*/, auto&& /*value*/, auto&& result) { - return result + 1; + auto const result = Reflection::FoldMembers(size_t{0}, [](auto&& result) { + return result + I; }); // clang-format on - CHECK(result == 5); + CHECK(result == 0 + 0 + 1 + 2 + 3 + 4); } struct S @@ -93,3 +93,12 @@ TEST_CASE("FoldMembers.value", "[reflection]") CHECK(result == 6); } + +TEST_CASE("MemberTypeOf", "[reflection]") +{ + static_assert(std::same_as, int>); + static_assert(std::same_as, float>); + static_assert(std::same_as, double>); + static_assert(std::same_as, std::string>); + static_assert(std::same_as, Person>); +}