diff --git a/TODO b/TODO index a621cd337..e8c995dbb 100644 --- a/TODO +++ b/TODO @@ -18,6 +18,7 @@ - ... WIP: +* HP: meta func/ctor size -> arity * HP: as_ref should be a qualified function, not a global one (no breaking change, ADL makes it work anyway) * HP: merge view and view pack * HP: invalid view auto-refresh diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 3a2b3c2b7..d1966af0a 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -688,8 +688,8 @@ struct meta_ctor { /** * @brief Returns the type of the i-th argument of a constructor. - * @param index The index of the argument of which to return the type. - * @return The type of the i-th argument of a constructor, if any. + * @param index Index of the argument of which to return the type. + * @return The type of the i-th argument of a constructor. */ [[nodiscard]] meta_type arg(size_type index) const ENTT_NOEXCEPT; @@ -900,8 +900,8 @@ struct meta_func { /** * @brief Returns the type of the i-th argument of a member function. - * @param index The index of the argument of which to return the type. - * @return The type of the i-th argument of a member function, if any. + * @param index Index of the argument of which to return the type. + * @return The type of the i-th argument of a member function. */ [[nodiscard]] inline meta_type arg(size_type index) const ENTT_NOEXCEPT; @@ -1163,6 +1163,44 @@ public: return node->is_associative_container; } + /** + * @brief Checks whether a type refers to a recognized class template + * specialization or not. + * @return True if the type is a recognized class template specialization, + * false otherwise. + */ + [[nodiscard]] bool is_template_specialization() const ENTT_NOEXCEPT { + return node->template_info.is_template_specialization; + } + + /** + * @brief Returns the number of template arguments, if any. + * @return The number of template arguments, if any. + */ + [[nodiscard]] size_type template_arity() const ENTT_NOEXCEPT { + return node->template_info.template_arity; + } + + /** + * @brief Returns a tag for the class template of the underlying type. + * + * @sa meta_class_template_tag + * + * @return The tag for the class template of the underlying type. + */ + [[nodiscard]] inline meta_type template_type() const ENTT_NOEXCEPT { + return is_template_specialization() ? node->template_info.template_type() : meta_type{}; + } + + /** + * @brief Returns the type of the i-th template argument of a type. + * @param index Index of the template argument of which to return the type. + * @return The type of the i-th template argument of a type. + */ + [[nodiscard]] inline meta_type template_arg(size_type index) const ENTT_NOEXCEPT { + return index < template_arity() ? node->template_info.template_arg(index) : meta_type{}; + } + /** * @brief Provides the number of dimensions of an array type. * @return The number of dimensions in case of array types, 0 otherwise. diff --git a/src/entt/meta/node.hpp b/src/entt/meta/node.hpp index e56e8b7ee..c1fd4f416 100644 --- a/src/entt/meta/node.hpp +++ b/src/entt/meta/node.hpp @@ -2,6 +2,7 @@ #define ENTT_META_NODE_HPP +#include #include #include #include @@ -17,6 +18,11 @@ namespace entt { +/*! @brief Utility class to disambiguate class templates. */ +template typename> +struct meta_class_template_tag {}; + + class meta_any; class meta_type; struct meta_handle; @@ -96,6 +102,15 @@ struct meta_func_node { }; +struct meta_template_info { + using size_type = std::size_t; + const bool is_template_specialization; + const size_type template_arity; + meta_type_node *(* const template_type)() ENTT_NOEXCEPT; + meta_type_node *(* const template_arg)(const size_type) ENTT_NOEXCEPT; +}; + + struct meta_type_node { using size_type = std::size_t; const type_info info; @@ -117,8 +132,9 @@ struct meta_type_node { const bool is_pointer_like; const bool is_sequence_container; const bool is_associative_container; + meta_template_info template_info; const size_type rank; - size_type(* const extent)(const size_type); + size_type(* const extent)(const size_type) ENTT_NOEXCEPT ; meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT; meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT; meta_ctor_node *def_ctor{nullptr}; @@ -157,15 +173,15 @@ class ENTT_API meta_node { static_assert(std::is_same_v>>, "Invalid type"); template - [[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence) { + [[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence) ENTT_NOEXCEPT { meta_type_node::size_type ext{}; ((ext = (dim == Index ? std::extent_v : ext)), ...); return ext; } - [[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) { + [[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT { if constexpr(std::is_default_constructible_v) { - static internal::meta_ctor_node node{ + static meta_ctor_node node{ type, nullptr, nullptr, @@ -180,8 +196,24 @@ class ENTT_API meta_node { } } + template typename Clazz, typename... Args> + [[nodiscard]] static meta_template_info template_info(type_identity>) ENTT_NOEXCEPT { + return { + true, + sizeof...(Args), + &meta_node>::resolve, + [](const std::size_t index) ENTT_NOEXCEPT { + return std::array{{internal::meta_info::resolve()...}}[index]; + } + }; + } + + [[nodiscard]] static meta_template_info template_info(...) ENTT_NOEXCEPT { + return { false, 0u, nullptr, nullptr }; + } + public: - [[nodiscard]] static internal::meta_type_node * resolve() ENTT_NOEXCEPT { + [[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT { static meta_type_node node{ type_id(), {}, @@ -202,10 +234,11 @@ public: is_meta_pointer_like_v, has_meta_sequence_container_traits_v, has_meta_associative_container_traits_v, + template_info(type_identity{}), std::rank_v, - [](meta_type_node::size_type dim) { return extent(dim, std::make_index_sequence>{}); }, + [](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence>{}); }, &meta_node>>::resolve, - &meta_node>>::resolve, + &meta_node>>>::resolve, meta_default_constructor(&node), meta_default_constructor(&node) }; diff --git a/test/entt/meta/meta_type.cpp b/test/entt/meta/meta_type.cpp index 4563dd3d2..de1acbd6f 100644 --- a/test/entt/meta/meta_type.cpp +++ b/test/entt/meta/meta_type.cpp @@ -599,3 +599,16 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) { ASSERT_TRUE(entt::resolve().data("rand"_hs).prop(property_t::value)); ASSERT_TRUE(entt::resolve().data("rand"_hs).prop(property_t::random)); } + +TEST_F(MetaType, ClassTemplate) { + ASSERT_FALSE(entt::resolve().is_template_specialization()); + ASSERT_EQ(entt::resolve().template_arity(), 0u); + ASSERT_EQ(entt::resolve().template_type(), entt::meta_type{}); + ASSERT_EQ(entt::resolve().template_arg(0u), entt::meta_type{}); + + ASSERT_TRUE(entt::resolve>().is_template_specialization()); + ASSERT_EQ(entt::resolve>().template_arity(), 1u); + ASSERT_EQ(entt::resolve>().template_type(), entt::resolve>()); + ASSERT_EQ(entt::resolve>().template_arg(0u), entt::resolve()); + ASSERT_EQ(entt::resolve>().template_arg(1u), entt::meta_type{}); +} \ No newline at end of file