/** @file reflect_struct_info.hpp * * Author: Roland Conybeare **/ #pragma once #include #include namespace xo { namespace reflect { /** Instructions for reflecting a struct: * * #include "xo/reflectutil/reflect_struct_info.hpp" // this file * * namespace xo { * namespace reflect { * // replacing X with the number of member variables in foo: * REFLECT_BASE_STRUCT_INFO(some::ns::foo, X); * * // for each member {member_0, member_1, ...} of foo, * // in the same order as they appear in class/struct decl: * REFLECT_STRUCT_MEMBER_INFO(some::ns::foo, 0, member(0)); * REFLECT_STRUCT_MEMBER_INFO(some::ns::foo, 1, member(1); * .. * // (last member will have index number X-1) * } * } * * These decls can appear anywhere after decl for some::ns::foo; * they must be made in the global namespace * (so that specializations appear in the xo::reflect namespace) * * Finally to permanently capture struct ingredients, * this statement must run at least once: * * xo::reflect::reflect_struct(); * **/ #define REFLECT_BASE_STRUCT_INFO_TBODY(qualified_struct_name, member_count) \ struct reflect_struct_traits { \ static constexpr std::size_t n_members = member_count; \ static constexpr std::size_t n_parents = 0; \ } #define REFLECT_BASE_STRUCT_INFO(qualified_struct_name, member_count) \ template<> \ REFLECT_BASE_STRUCT_INFO_TBODY(qualified_struct_name, member_count) #define REFLECT_STRUCT_MEMBER_INFO_TBODY(qualified_struct_name, member_ix, member_name) \ struct reflect_struct_member { \ constexpr auto get() const { \ return reflect_struct_member_aux(xo::flatstring(#member_name), \ &qualified_struct_name::member_name##_); \ } \ }; #define REFLECT_STRUCT_MEMBER_INFO(qualified_struct_name, member_ix, member_name) \ template <> \ REFLECT_STRUCT_MEMBER_INFO_TBODY(qualified_struct_name, member_ix, member_name) /** @class reflect_struct_traits * * @brief header-only ingredients for reflecting a struct * * A class/struct T to be reflected should provide specializations * of * - xo::reflect::reflect_struct_traits<> * - xo::reflect::reflect_struct_member<> * - xo::reflect::reflect_struct_parent<> [aspirational, not yet] * * For example: * * @code * * namespace foo { * struct mycomplex { double real_, double imag_; }; * } * * namespace xo { * namespace reflect { * template <> * struct reflect_struct_traits { * * // number of member variables * static constexpr std::size_t n_members = 2; * * // number of parent structs * // (i.e. directly inherited structs) * static constexpr std::size_t n_parents = 0; * }; * } * } * * // or use convenience macro (must be in global namespace) * REFLECT_BASE_STRUCT_INFO(foo::mycomplex, 2); * * @endcode **/ template struct reflect_struct_traits; /** @class reflect_struct_member * @brief reflection ingredients for a particular struct member * * A class/struct T to be reflected should provide specializations * of * - xo::reflect::reflect_struct_traits<> * - xo::reflect::reflect_struct_member<> * - xo::reflect::reflect_struct_parent<> [aspirational, not yet] * * For example: * * @code * * namespace foo { * struct mycomplex { double real_, double imag_; }; * } * * namespace xo { * namespace reflect { * // reflect foo::mycomplex::real_ * template <> * struct reflect_struct_member { * constexpr auto operator()() const { return reflect_struct_member_aux(xo::flatstring("real"), &foo::mycomplex::real_); } * }; * * // reflect foo::mycomplex::imag_ * template <> * struct reflect_struct_member { * constexpr auto operator()() const { return reflect_struct_member_aux(xo::flatstring("imag"), &foo::mycomplex::imag_); } * }; * } * } * * // or use convenience macro (must be invoked from global namespace) * REFLECT_STRUCT_MEMBER_INFO(foo::mycomplex, 0, real); * REFLECT_STRUCT_MEMBER_INFO(foo::mycomplex, 1, imag); * * @endcode **/ template struct reflect_struct_member; // ---------------------------------------------------------------- template struct reflect_struct_member_info { //using struct_type = StructT; using owner_type = OwnerT; using member_type = MemberT; using member_name_type = MemberNameT; constexpr reflect_struct_member_info(const MemberNameT & member_name, MemberT OwnerT::* member_addr) : member_name_{member_name}, member_addr_{member_addr} {} MemberNameT member_name_; MemberT OwnerT::* member_addr_; }; // ---------------------------------------------------------------- template constexpr auto reflect_struct_member_aux(const MemberNameT & member_name, MemberT OwnerT:: * member_addr) { return reflect_struct_member_info (member_name, member_addr); }; } /*namespace reflect*/ } /*namespace xo*/ /** end reflect_struct_info.hpp **/