// Copyright Epic Games, Inc. All Rights Reserved. #include "PlainPropsCtti.h" #include #include namespace PlainProps::Test { enum class E1 : uint8_t { A, B }; namespace Actual { PP_REFLECT_ENUM(PlainProps::Test, E1, A, B); } namespace Expect { struct E1_Ctti { static constexpr char Name[] = "E1"; using Type = ::PlainProps::Test::E1; static constexpr int NumEnumerators = 2; static constexpr struct { const char* Name; Type Constant; } Enumerators[] = { {"A", Type::A}, {"B", Type::B} }; }; } static_assert(std::string_view(Actual::E1_Ctti::Name) == std::string_view(Expect::E1_Ctti::Name)); static_assert(std::is_same_v); static_assert(Actual::E1_Ctti::NumEnumerators == Expect::E1_Ctti::NumEnumerators); static_assert(Actual::E1_Ctti::Enumerators[0].Constant == Expect::E1_Ctti::Enumerators[0].Constant); static_assert(Actual::E1_Ctti::Enumerators[1].Constant == Expect::E1_Ctti::Enumerators[1].Constant); static_assert(std::string_view(Actual::E1_Ctti::Enumerators[0].Name) == std::string_view(Expect::E1_Ctti::Enumerators[0].Name)); static_assert(std::string_view(Actual::E1_Ctti::Enumerators[1].Name) == std::string_view(Expect::E1_Ctti::Enumerators[1].Name)); ////////////////////////////////////////////////////////////////////////// struct S1 { float x; int y; }; namespace Actual { PP_REFLECT_STRUCT(PlainProps::Test, S1, void, x, y); } namespace Expect { struct S1_Ctti { static constexpr char Name[] = "S1"; using Type = ::PlainProps::Test::S1; using Super = void; static constexpr int NumVars = 2; template struct Var; }; template<> struct S1_Ctti::Var<2-2> { static constexpr char Name[] = "x"; using Type = decltype(::PlainProps::Test::S1::x); static constexpr auto Pointer = &::PlainProps::Test::S1::x; static constexpr std::size_t Offset = offsetof(::PlainProps::Test::S1, x); static constexpr int Index = 2-2; }; template<> struct S1_Ctti::Var<2-1> { static constexpr char Name[] = "y"; using Type = decltype(::PlainProps::Test::S1::y); static constexpr auto Pointer = &::PlainProps::Test::S1::y; static constexpr std::size_t Offset = offsetof(::PlainProps::Test::S1, y); static constexpr int Index = 2-1; }; } template static constexpr bool AssertVarEquivalence() { static_assert(std::string_view(Actual::Name) == std::string_view(Expect::Name)); static_assert(std::is_same_v); static_assert(Actual::Offset == Expect::Offset); static_assert(Actual::Pointer == Expect::Pointer); static_assert(Actual::Index == Expect::Index); return true; } static_assert(std::string_view(Actual::S1_Ctti::Name) == std::string_view(Expect::S1_Ctti::Name)); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(Actual::S1_Ctti::NumVars == Expect::S1_Ctti::NumVars); static_assert(AssertVarEquivalence, Expect::S1_Ctti::Var<0>>()); static_assert(AssertVarEquivalence, Expect::S1_Ctti::Var<1>>()); // CttiOf only works when CTTI exists in same or parent namespace, it uses argument dependent lookup // to find the "canonical" CTTI if exists. Regenerate S1_Ctti in S1's namespace to test it. PP_REFLECT_STRUCT(PlainProps::Test, S1, void, x, y); static_assert(std::is_same_v, S1_Ctti>); ////////////////////////////////////////////////////////////////////////// template struct S2 { bool _; // unreflected T a; }; PP_REFLECT_STRUCT_TEMPLATE(PlainProps::Test, S2, void, a); static_assert(std::string_view(CttiOf>::Name) == std::string_view("S2")); static_assert(std::is_same_v>::Type, S2>); static_assert(std::is_same_v>::TemplateArgs, std::tuple>); static_assert(CttiOf>::NumVars == 1); static_assert(CttiOf>::Var<0>::Name == std::string_view("a")); static_assert(CttiOf>::Var<0>::Offset == offsetof(S2, a)); }