Jelajahi Sumber

meta:
* meta_any: convert -> allow_cast
* support for const references
* as_cref_t policy

Michele Caini 5 tahun lalu
induk
melakukan
c52f16f5b8

+ 5 - 1
TODO

@@ -15,10 +15,12 @@
   - spatial query
   - spatial query
   - runtime types pool
   - runtime types pool
   - off-line/off-memory/remote
   - off-line/off-memory/remote
-  - poly
   - ...
   - ...
 
 
 WIP:
 WIP:
+* HP: any/meta_any/poly: ::REF -> ::CREF?
+* HP: meta, support for custom deref function other than operator*
+* HP: meta, as_cref_t other than as_ref_t
 * HP: headless (sparse set only) view
 * HP: headless (sparse set only) view
 * HP: pass the registry to pools, basic poly storage should have only component member
 * HP: pass the registry to pools, basic poly storage should have only component member
 * HP: make view pack work also with groups, make packs input iterator only, add view adapter for external sources
 * HP: make view pack work also with groups, make packs input iterator only, add view adapter for external sources
@@ -27,6 +29,8 @@ WIP:
 * HP: any/poly: configurable sbo size, compile-time policies like sbo-required.
 * HP: any/poly: configurable sbo size, compile-time policies like sbo-required.
 * HP: registry: use a poly object for pools, no more pool_data type.
 * HP: registry: use a poly object for pools, no more pool_data type.
 * HP: make runtime views use opaque storage and therefore return also elements.
 * HP: make runtime views use opaque storage and therefore return also elements.
+* HP: meta_sequence_container & Co can be replaced by a poly object.
+* HP: poly: support for data members
 * suppress warnings in meta.hpp (uninitialized members)
 * suppress warnings in meta.hpp (uninitialized members)
 * add exclude-only views to combine with packs
 * add exclude-only views to combine with packs
 * deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
 * deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views

+ 14 - 12
docs/md/meta.md

@@ -215,9 +215,9 @@ const bool equal = (any == other);
 Also, `meta_any` adds support for containers and pointer-like types (see the
 Also, `meta_any` adds support for containers and pointer-like types (see the
 following sections for more details).<br/>
 following sections for more details).<br/>
 Similar to `any`, this class can also be used to create _aliases_ for unmanaged
 Similar to `any`, this class can also be used to create _aliases_ for unmanaged
-objects either upon construction using `std::ref` or from an existing instance
-by means of the `as_ref` function. However, unlike `any`,` meta_any` treats an
-empty instance and one initialized with `void` differently:
+objects either upon construction using `std::ref` and `std::cref` or from an
+existing instance by means of the `as_ref` function. However, unlike `any`,
+`meta_any` treats an empty instance and one initialized with `void` differently:
 
 
 ```cpp
 ```cpp
 entt::meta_any empty{};
 entt::meta_any empty{};
@@ -228,9 +228,10 @@ While `any` treats both objects as empty, `meta_any` treats objects initialized
 with `void` as if they were _valid_ ones. This allows to differentiate between
 with `void` as if they were _valid_ ones. This allows to differentiate between
 failed function calls and function calls that are successful but return
 failed function calls and function calls that are successful but return
 nothing.<br/>
 nothing.<br/>
-Finally, the member functions `try_cast`, `cast` and `convert` are used to know
-if the underlying object has a given type as a base or if it can be converted
-implicitly to it. There is in fact no `any_cast` equivalent for `meta_any`.
+Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
+cast the underlying object to a given type (either a reference or a value type)
+or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
+resulting object. There is in fact no `any_cast` equivalent for `meta_any`.
 
 
 ## Enjoy the runtime
 ## Enjoy the runtime
 
 
@@ -684,13 +685,14 @@ There are a few alternatives available at the moment:
   entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
   entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
   ```
   ```
 
 
-* The _as-ref_ policy, associated with the type `entt::as_ref_t`.<br/>
-  It allows to build wrappers that act as references to unmanaged objects.
-  Modifying the object contained in the wrapper for which the _reference_ was
-  requested will make it possible to directly modify the instance used to
+* The _as-ref_ and _as-cref_ policies, associated with the types
+  `entt::as_ref_t` and `entt::as_cref_t`.<br/>
+  They allow to build wrappers that act as references to unmanaged objects.
+  Accessing the object contained in the wrapper for which the _reference_ was
+  requested will make it possible to directly access the instance used to
   initialize the wrapper itself.<br/>
   initialize the wrapper itself.<br/>
-  This policy works with constructors (for example, when objects are taken from
-  an external container rather than created on demand), data members and
+  These policies work with constructors (for example, when objects are taken
+  from an external container rather than created on demand), data members and
   functions in general (as long as their return types are lvalue references).
   functions in general (as long as their return types are lvalue references).
 
 
   As an example of use:
   As an example of use:

+ 39 - 39
src/entt/meta/container.hpp

@@ -273,12 +273,12 @@ struct fixed_sequence_container {
 template<typename Type, typename... Args>
 template<typename Type, typename... Args>
 struct meta_sequence_container_traits<std::vector<Type, Args...>>
 struct meta_sequence_container_traits<std::vector<Type, Args...>>
         : container_traits<
         : container_traits<
-            std::vector<Type, Args...>,
-            basic_container,
-            basic_dynamic_container,
-            basic_sequence_container,
-            dynamic_sequence_container
-        >
+              std::vector<Type, Args...>,
+              basic_container,
+              basic_dynamic_container,
+              basic_sequence_container,
+              dynamic_sequence_container
+          >
 {};
 {};
 
 
 
 
@@ -290,11 +290,11 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
 template<typename Type, auto N>
 template<typename Type, auto N>
 struct meta_sequence_container_traits<std::array<Type, N>>
 struct meta_sequence_container_traits<std::array<Type, N>>
         : container_traits<
         : container_traits<
-            std::array<Type, N>,
-            basic_container,
-            basic_sequence_container,
-            fixed_sequence_container
-        >
+              std::array<Type, N>,
+              basic_container,
+              basic_sequence_container,
+              fixed_sequence_container
+          >
 {};
 {};
 
 
 
 
@@ -307,13 +307,13 @@ struct meta_sequence_container_traits<std::array<Type, N>>
 template<typename Key, typename Value, typename... Args>
 template<typename Key, typename Value, typename... Args>
 struct meta_associative_container_traits<std::map<Key, Value, Args...>>
 struct meta_associative_container_traits<std::map<Key, Value, Args...>>
         : container_traits<
         : container_traits<
-            std::map<Key, Value, Args...>,
-            basic_container,
-            basic_associative_container,
-            basic_dynamic_container,
-            basic_dynamic_associative_container,
-            dynamic_associative_key_value_container
-        >
+              std::map<Key, Value, Args...>,
+              basic_container,
+              basic_associative_container,
+              basic_dynamic_container,
+              basic_dynamic_associative_container,
+              dynamic_associative_key_value_container
+          >
 {
 {
     /*! @brief Mapped type of the sequence container. */
     /*! @brief Mapped type of the sequence container. */
     using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
     using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
@@ -330,13 +330,13 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
 template<typename Key, typename Value, typename... Args>
 template<typename Key, typename Value, typename... Args>
 struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
 struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
         : container_traits<
         : container_traits<
-            std::unordered_map<Key, Value, Args...>,
-            basic_container,
-            basic_associative_container,
-            basic_dynamic_container,
-            basic_dynamic_associative_container,
-            dynamic_associative_key_value_container
-        >
+              std::unordered_map<Key, Value, Args...>,
+              basic_container,
+              basic_associative_container,
+              basic_dynamic_container,
+              basic_dynamic_associative_container,
+              dynamic_associative_key_value_container
+          >
 {
 {
     /*! @brief Mapped type of the sequence container. */
     /*! @brief Mapped type of the sequence container. */
     using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
     using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
@@ -351,13 +351,13 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
 template<typename Key, typename... Args>
 template<typename Key, typename... Args>
 struct meta_associative_container_traits<std::set<Key, Args...>>
 struct meta_associative_container_traits<std::set<Key, Args...>>
         : container_traits<
         : container_traits<
-            std::set<Key, Args...>,
-            basic_container,
-            basic_associative_container,
-            basic_dynamic_container,
-            basic_dynamic_associative_container,
-            dynamic_associative_key_only_container
-        >
+              std::set<Key, Args...>,
+              basic_container,
+              basic_associative_container,
+              basic_dynamic_container,
+              basic_dynamic_associative_container,
+              dynamic_associative_key_only_container
+          >
 {};
 {};
 
 
 
 
@@ -370,13 +370,13 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
 template<typename Key, typename... Args>
 template<typename Key, typename... Args>
 struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
 struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
         : container_traits<
         : container_traits<
-            std::unordered_set<Key, Args...>,
-            basic_container,
-            basic_associative_container,
-            basic_dynamic_container,
-            basic_dynamic_associative_container,
-            dynamic_associative_key_only_container
-        >
+              std::unordered_set<Key, Args...>,
+              basic_container,
+              basic_associative_container,
+              basic_dynamic_container,
+              basic_dynamic_associative_container,
+              dynamic_associative_key_only_container
+          >
 {};
 {};
 
 
 
 

+ 52 - 48
src/entt/meta/factory.hpp

@@ -35,8 +35,8 @@ struct meta_function_helper;
 
 
 template<typename Ret, typename... Args, bool Const, bool Static>
 template<typename Ret, typename... Args, bool Const, bool Static>
 struct meta_function_helper<Ret(Args...), Const, Static> {
 struct meta_function_helper<Ret(Args...), Const, Static> {
-    using return_type = std::remove_cv_t<std::remove_reference_t<Ret>>;
-    using args_type = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
+    using return_type = Ret;
+    using args_type = type_list<Args...>;
 
 
     static constexpr auto is_static = Static;
     static constexpr auto is_static = Static;
     static constexpr auto is_const = Const;
     static constexpr auto is_const = Const;
@@ -48,12 +48,12 @@ struct meta_function_helper<Ret(Args...), Const, Static> {
 
 
 
 
 template<typename Type, typename Ret, typename... Args, typename Class>
 template<typename Type, typename Ret, typename... Args, typename Class>
-constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(std::add_lvalue_reference_t<Class>, Args...)>, true, !std::is_same_v<Type, Class>>
+constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(Class &, Args...)>, true, !std::is_same_v<Type, Class>>
 to_meta_function_helper(Ret(Class:: *)(Args...) const);
 to_meta_function_helper(Ret(Class:: *)(Args...) const);
 
 
 
 
 template<typename Type, typename Ret, typename... Args, typename Class>
 template<typename Type, typename Ret, typename... Args, typename Class>
-constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(std::add_lvalue_reference_t<Class>, Args...)>, false, !std::is_same_v<Type, Class>>
+constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(Class &, Args...)>, false, !std::is_same_v<Type, Class>>
 to_meta_function_helper(Ret(Class:: *)(Args...));
 to_meta_function_helper(Ret(Class:: *)(Args...));
 
 
 
 
@@ -70,12 +70,13 @@ template<typename Type, typename Candidate>
 using meta_function_helper_t = decltype(to_meta_function_helper<Type>(std::declval<Candidate>()));
 using meta_function_helper_t = decltype(to_meta_function_helper<Type>(std::declval<Candidate>()));
 
 
 
 
-template<typename Type, typename... Args, std::size_t... Indexes>
-[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence<Indexes...>) {
-    [[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast<Args>()...);
-    return ((std::get<Indexes>(direct) || (args+Indexes)->convert<Args>()) && ...)
-            ? Type{(std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<Args>())...}
-            : meta_any{};
+template<typename Type, typename... Args, std::size_t... Index>
+[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence<Index...>) {
+    if(((args+Index)->allow_cast<Args>() && ...)) {
+        return Type{(args+Index)->cast<Args>()...};
+    }
+
+    return {};
 }
 }
 
 
 
 
@@ -85,11 +86,11 @@ template<typename Type, auto Data>
 
 
     if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
     if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
         using helper_type = meta_function_helper_t<Type, decltype(Data)>;
         using helper_type = meta_function_helper_t<Type, decltype(Data)>;
-        using data_type = std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
+        using data_type = type_list_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
 
 
         if(auto * const clazz = instance->try_cast<Type>(); clazz) {
         if(auto * const clazz = instance->try_cast<Type>(); clazz) {
-            if(auto * const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
-                std::invoke(Data, *clazz, direct ? *direct : value.cast<data_type>());
+            if(value.allow_cast<data_type>()) {
+                std::invoke(Data, *clazz, value.cast<data_type>());
                 accepted = true;
                 accepted = true;
             }
             }
         }
         }
@@ -98,8 +99,8 @@ template<typename Type, auto Data>
 
 
         if constexpr(!std::is_array_v<data_type>) {
         if constexpr(!std::is_array_v<data_type>) {
             if(auto * const clazz = instance->try_cast<Type>(); clazz) {
             if(auto * const clazz = instance->try_cast<Type>(); clazz) {
-                if(auto * const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
-                    std::invoke(Data, clazz) = (direct ? *direct : value.cast<data_type>());
+                if(value.allow_cast<data_type>()) {
+                    std::invoke(Data, clazz) = value.cast<data_type>();
                     accepted = true;
                     accepted = true;
                 }
                 }
             }
             }
@@ -108,8 +109,8 @@ template<typename Type, auto Data>
         using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
         using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
 
 
         if constexpr(!std::is_array_v<data_type>) {
         if constexpr(!std::is_array_v<data_type>) {
-            if(auto * const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
-                *Data = (direct ? *direct : value.cast<data_type>());
+            if(value.allow_cast<data_type>()) {
+                *Data = value.cast<data_type>();
                 accepted = true;
                 accepted = true;
             }
             }
         }
         }
@@ -126,6 +127,8 @@ template<typename Type, auto Data, typename Policy>
             return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
             return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
         } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
         } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
             return meta_any{std::ref(std::forward<decltype(value)>(value))};
             return meta_any{std::ref(std::forward<decltype(value)>(value))};
+        } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+            return meta_any{std::cref(std::forward<decltype(value)>(value))};
         } else {
         } else {
             static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
             static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
             return meta_any{std::forward<decltype(value)>(value)};
             return meta_any{std::forward<decltype(value)>(value)};
@@ -133,13 +136,13 @@ template<typename Type, auto Data, typename Policy>
     };
     };
 
 
     if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
     if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
-        auto * const clazz = instance->try_cast<Type>();
+        auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type *>, const Type, Type>>();
         return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
         return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
     } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
     } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
         if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
         if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
             return meta_any{};
             return meta_any{};
         } else {
         } else {
-            auto * const clazz = instance->try_cast<Type>();
+            auto * const clazz = instance->try_cast<std::conditional_t<std::is_same_v<Policy, as_ref_t>, Type, const Type>>();
             return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
             return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
         }
         }
     } else if constexpr(std::is_pointer_v<std::decay_t<decltype(Data)>>) {
     } else if constexpr(std::is_pointer_v<std::decay_t<decltype(Data)>>) {
@@ -154,38 +157,39 @@ template<typename Type, auto Data, typename Policy>
 }
 }
 
 
 
 
-template<typename Type, auto Candidate, typename Policy, std::size_t... Indexes>
-[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Indexes...>) {
+template<typename Type, auto Candidate, typename Policy, std::size_t... Index>
+[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Index...>) {
     using helper_type = meta_function_helper_t<Type, decltype(Candidate)>;
     using helper_type = meta_function_helper_t<Type, decltype(Candidate)>;
 
 
-    auto dispatch = [](auto *... params) {
-        if constexpr(std::is_void_v<typename helper_type::return_type> || std::is_same_v<Policy, as_void_t>) {
-            std::invoke(Candidate, *params...);
+    auto dispatch = [](auto &&... params) {
+        if constexpr(std::is_void_v<std::remove_cv_t<typename helper_type::return_type>> || std::is_same_v<Policy, as_void_t>) {
+            std::invoke(Candidate, std::forward<decltype(params)>(params)...);
             return meta_any{std::in_place_type<void>};
             return meta_any{std::in_place_type<void>};
         } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
         } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
-            return meta_any{std::ref(std::invoke(Candidate, *params...))};
+            return meta_any{std::ref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
+        } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+            return meta_any{std::cref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
         } else {
         } else {
             static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
             static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
-            return meta_any{std::invoke(Candidate, *params...)};
+            return meta_any{std::invoke(Candidate, std::forward<decltype(params)>(params)...)};
         }
         }
     };
     };
 
 
-    [[maybe_unused]] const auto direct = std::make_tuple([](meta_any *any, auto *value) {
-        using arg_type = std::remove_reference_t<decltype(*value)>;
-
-        if(!value && any->convert<arg_type>()) {
-            value = any->try_cast<arg_type>();
+    if constexpr(std::is_invocable_v<decltype(Candidate), const Type &, type_list_element_t<Index, typename helper_type::args_type>...>) {
+        if(const auto * const clazz = instance->try_cast<const Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
+            return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
+        }
+    } else if constexpr(std::is_invocable_v<decltype(Candidate), Type &, type_list_element_t<Index, typename helper_type::args_type>...>) {
+        if(auto * const clazz = instance->try_cast<Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
+            return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
         }
         }
-
-        return value;
-    }(args+Indexes, (args+Indexes)->try_cast<std::tuple_element_t<Indexes, typename helper_type::args_type>>())...);
-
-    if constexpr(std::is_invocable_v<decltype(Candidate), std::add_lvalue_reference_t<Type>, std::tuple_element_t<Indexes, typename helper_type::args_type>...>) {
-        auto * const clazz = instance->try_cast<Type>();
-        return (clazz && (std::get<Indexes>(direct) && ...)) ? dispatch(clazz, std::get<Indexes>(direct)...) : meta_any{};
     } else {
     } else {
-        return (std::get<Indexes>(direct) && ...) ? dispatch(std::get<Indexes>(direct)...) : meta_any{};
+        if(((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
+            return dispatch((args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
+        }
     }
     }
+
+    return meta_any{};
 }
 }
 
 
 
 
@@ -469,17 +473,17 @@ public:
     template<auto Candidate, typename Policy = as_is_t>
     template<auto Candidate, typename Policy = as_is_t>
     auto ctor() ENTT_NOEXCEPT {
     auto ctor() ENTT_NOEXCEPT {
         using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
         using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
-        static_assert(std::is_same_v<typename helper_type::return_type, Type>, "The function doesn't return an object of the required type");
+        static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename helper_type::return_type>>, Type>, "The function doesn't return an object of the required type");
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
 
 
         static internal::meta_ctor_node node{
         static internal::meta_ctor_node node{
             type,
             type,
             nullptr,
             nullptr,
             nullptr,
             nullptr,
-            std::tuple_size_v<typename helper_type::args_type>,
+            helper_type::args_type::size,
             &helper_type::arg,
             &helper_type::arg,
             [](meta_any * const any) {
             [](meta_any * const any) {
-                return internal::invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
+                return internal::invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<helper_type::args_type::size>{});
             }
             }
         };
         };
 
 
@@ -509,10 +513,10 @@ public:
             type,
             type,
             nullptr,
             nullptr,
             nullptr,
             nullptr,
-            std::tuple_size_v<typename helper_type::args_type>,
+            helper_type::args_type::size,
             &helper_type::arg,
             &helper_type::arg,
             [](meta_any * const any) {
             [](meta_any * const any) {
-                return internal::construct<Type, std::remove_cv_t<std::remove_reference_t<Args>>...>(any, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
+                return internal::construct<Type, Args...>(any, std::make_index_sequence<helper_type::args_type::size>{});
             }
             }
         };
         };
 
 
@@ -583,7 +587,7 @@ public:
                 nullptr,
                 nullptr,
                 true,
                 true,
                 &internal::meta_info<data_type>::resolve,
                 &internal::meta_info<data_type>::resolve,
-                []() -> std::remove_const_t<decltype(internal::meta_data_node::set)> {
+                []() -> std::remove_cv_t<decltype(internal::meta_data_node::set)> {
                     if constexpr(std::is_same_v<Type, data_type> || std::is_const_v<data_type>) {
                     if constexpr(std::is_same_v<Type, data_type> || std::is_const_v<data_type>) {
                         return nullptr;
                         return nullptr;
                     } else {
                     } else {
@@ -635,7 +639,7 @@ public:
             nullptr,
             nullptr,
             false,
             false,
             &internal::meta_info<underlying_type>::resolve,
             &internal::meta_info<underlying_type>::resolve,
-            []() -> std::remove_const_t<decltype(internal::meta_data_node::set)> {
+            []() -> std::remove_cv_t<decltype(internal::meta_data_node::set)> {
                 if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>)) {
                 if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>)) {
                     return nullptr;
                     return nullptr;
                 } else {
                 } else {
@@ -677,13 +681,13 @@ public:
             type,
             type,
             nullptr,
             nullptr,
             nullptr,
             nullptr,
-            std::tuple_size_v<typename helper_type::args_type>,
+            helper_type::args_type::size,
             helper_type::is_const,
             helper_type::is_const,
             helper_type::is_static,
             helper_type::is_static,
             &internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
             &internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
             &helper_type::arg,
             &helper_type::arg,
             [](meta_handle instance, meta_any *args) {
             [](meta_handle instance, meta_any *args) {
-                return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
+                return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<helper_type::args_type::size>{});
             }
             }
         };
         };
 
 

+ 49 - 45
src/entt/meta/meta.hpp

@@ -330,7 +330,7 @@ public:
     [[nodiscard]] const Type * try_cast() const {
     [[nodiscard]] const Type * try_cast() const {
         if(node) {
         if(node) {
             if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
             if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
-                return static_cast<const Type *>(storage.data());
+                return any_cast<Type>(&storage);
             } else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
             } else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
                 return static_cast<const Type *>(base->cast(storage.data()));
                 return static_cast<const Type *>(base->cast(storage.data()));
             }
             }
@@ -344,12 +344,12 @@ public:
     [[nodiscard]] Type * try_cast() {
     [[nodiscard]] Type * try_cast() {
         if(node) {
         if(node) {
             if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
             if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
-                return static_cast<Type *>(storage.data());
+                return any_cast<Type>(&storage);
             } else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
             } else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
-                return static_cast<Type *>(const_cast<void *>(base->cast(storage.data())));
+                return static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(base->cast(static_cast<constness_as_t<any, Type> &>(storage).data())));
             }
             }
         }
         }
-
+        
         return nullptr;
         return nullptr;
     }
     }
 
 
@@ -367,7 +367,7 @@ public:
      */
      */
     template<typename Type>
     template<typename Type>
     [[nodiscard]] Type cast() const {
     [[nodiscard]] Type cast() const {
-        auto * const actual = try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
+        auto * const actual = try_cast<std::remove_reference_t<Type>>();
         ENTT_ASSERT(actual);
         ENTT_ASSERT(actual);
         return static_cast<Type>(*actual);
         return static_cast<Type>(*actual);
     }
     }
@@ -375,30 +375,26 @@ public:
     /*! @copydoc cast */
     /*! @copydoc cast */
     template<typename Type>
     template<typename Type>
     [[nodiscard]] Type cast() {
     [[nodiscard]] Type cast() {
-        if constexpr(!std::is_reference_v<Type> || std::is_const_v<std::remove_reference_t<Type>>) {
-            // last attempt to make wrappers for const references return their values
-            auto * const actual = std::as_const(*this).try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
-            ENTT_ASSERT(actual);
-            return static_cast<Type>(*actual);
-        } else {
-            auto * const actual = try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
-            ENTT_ASSERT(actual);
-            return static_cast<Type>(*actual);
-        }
+        // forces const on non-reference types to make them work also with wrappers for const references
+        auto * const actual = try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>();
+        ENTT_ASSERT(actual);
+        return static_cast<Type>(*actual);
     }
     }
 
 
     /**
     /**
-     * @brief Tries to convert an instance to a given type and returns it.
-     * @tparam Type Type to which to convert the instance.
-     * @return A valid meta any object if the conversion is possible, an invalid
-     * one otherwise.
+     * @brief Tries to make an instance castable to a certain type.
+     * @tparam Type Type to which the cast is requested.
+     * @return A valid meta any object if there exists a a viable conversion
+     * that makes the cast possible, an invalid object otherwise.
      */
      */
     template<typename Type>
     template<typename Type>
-    [[nodiscard]] meta_any convert() const {
-        if(node) {
-            if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
-                return *this;
-            } else if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info](const auto *curr) { return curr->type()->info == info; }, node); conv) {
+    [[nodiscard]] meta_any allow_cast() const {
+        if(try_cast<std::remove_reference_t<Type>>() != nullptr) {
+            return as_ref(*this);
+        } else if(node) {
+            if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info<Type>::resolve()->info](const auto *curr) {
+                return curr->type()->info == info;
+            }, node); conv) {
                 return conv->conv(storage.data());
                 return conv->conv(storage.data());
             }
             }
         }
         }
@@ -407,22 +403,25 @@ public:
     }
     }
 
 
     /**
     /**
-     * @brief Tries to convert an instance to a given type.
-     * @tparam Type Type to which to convert the instance.
-     * @return True if the conversion is possible, false otherwise.
+     * @brief Tries to make an instance castable to a certain type.
+     * @tparam Type Type to which the cast is requested.
+     * @return True if there exists a a viable conversion that makes the cast
+     * possible, false otherwise.
      */
      */
     template<typename Type>
     template<typename Type>
-    bool convert() {
-        bool valid = (node && node->info == internal::meta_info<Type>::resolve()->info);
-
-        if(!valid) {
-            if(auto any = std::as_const(*this).convert<Type>(); any) {
-                swap(any, *this);
-                valid = true;
+    bool allow_cast() {
+        if(try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>() != nullptr) {
+            return true;
+        } else if(node) {
+            if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info<Type>::resolve()->info](const auto *curr) {
+                return curr->type()->info == info;
+            }, node); conv) {
+                swap(conv->conv(std::as_const(storage).data()), *this);
+                return true;
             }
             }
         }
         }
 
 
-        return valid;
+        return false;
     }
     }
 
 
     /**
     /**
@@ -570,6 +569,11 @@ struct meta_handle {
         return &any;
         return &any;
     }
     }
 
 
+    /*! @brief operator-> */
+    [[nodiscard]] const meta_any * operator->() const {
+        return &any;
+    }
+
 private:
 private:
     meta_any any;
     meta_any any;
 };
 };
@@ -1767,8 +1771,8 @@ struct meta_sequence_container::meta_sequence_container_proxy {
     }
     }
 
 
     [[nodiscard]] static std::pair<iterator, bool> insert(void *container, iterator it, meta_any value) {
     [[nodiscard]] static std::pair<iterator, bool> insert(void *container, iterator it, meta_any value) {
-        if(const auto *v_ptr = value.try_cast<typename traits_type::value_type>(); v_ptr || value.convert<typename traits_type::value_type>()) {
-            auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>(), v_ptr ? *v_ptr : value.cast<const typename traits_type::value_type &>());
+        if(value.allow_cast<const typename traits_type::value_type &>()) {
+            auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>(), value.cast<const typename traits_type::value_type &>());
             return { iterator{std::move(ret.first)}, ret.second };
             return { iterator{std::move(ret.first)}, ret.second };
         }
         }
 
 
@@ -2034,12 +2038,12 @@ struct meta_associative_container::meta_associative_container_proxy {
     }
     }
 
 
     [[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
     [[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
-        if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
+        if(key.allow_cast<const typename traits_type::key_type &>()) {
             if constexpr(is_key_only_meta_associative_container_v<Type>) {
             if constexpr(is_key_only_meta_associative_container_v<Type>) {
-                return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>());
+                return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
             } else {
             } else {
-                if(const auto *m_ptr = value.try_cast<typename traits_type::mapped_type>(); m_ptr || value.convert<typename traits_type::mapped_type>()) {
-                    return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>(), m_ptr ? *m_ptr : value.cast<const typename traits_type::mapped_type &>());
+                if(value.allow_cast<const typename traits_type::mapped_type &>()) {
+                    return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>(), value.cast<const typename traits_type::mapped_type &>());
                 }
                 }
             }
             }
         }
         }
@@ -2048,16 +2052,16 @@ struct meta_associative_container::meta_associative_container_proxy {
     }
     }
 
 
     [[nodiscard]] static bool erase(void *container, meta_any key) {
     [[nodiscard]] static bool erase(void *container, meta_any key) {
-        if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
-            return traits_type::erase(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>());
+        if(key.allow_cast<const typename traits_type::key_type &>()) {
+            return traits_type::erase(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
         }
         }
 
 
         return false;
         return false;
     }
     }
 
 
     [[nodiscard]] static iterator find(void *container, meta_any key) {
     [[nodiscard]] static iterator find(void *container, meta_any key) {
-        if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
-            return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>())};
+        if(key.allow_cast<const typename traits_type::key_type &>()) {
+            return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>())};
         }
         }
 
 
         return {};
         return {};

+ 4 - 0
src/entt/meta/policy.hpp

@@ -9,6 +9,10 @@ namespace entt {
 struct as_ref_t {};
 struct as_ref_t {};
 
 
 
 
+/*! @brief Empty class type used to request the _as cref_ policy. */
+struct as_cref_t {};
+
+
 /*! @brief Empty class type used to request the _as-is_ policy. */
 /*! @brief Empty class type used to request the _as-is_ policy. */
 struct as_is_t {};
 struct as_is_t {};
 
 

+ 10 - 10
test/entt/meta/meta_any.cpp

@@ -596,11 +596,11 @@ TEST_F(MetaAny, Convert) {
 
 
     ASSERT_TRUE(any);
     ASSERT_TRUE(any);
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
-    ASSERT_TRUE(any.convert<double>());
-    ASSERT_FALSE(any.convert<char>());
+    ASSERT_TRUE(any.allow_cast<double>());
+    ASSERT_FALSE(any.allow_cast<char>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.cast<double>(), 42.);
     ASSERT_EQ(any.cast<double>(), 42.);
-    ASSERT_TRUE(any.convert<int>());
+    ASSERT_TRUE(any.allow_cast<int>());
     ASSERT_EQ(any.type(), entt::resolve<int>());
     ASSERT_EQ(any.type(), entt::resolve<int>());
     ASSERT_EQ(any.cast<int>(), 42);
     ASSERT_EQ(any.cast<int>(), 42);
 }
 }
@@ -610,12 +610,12 @@ TEST_F(MetaAny, ConstConvert) {
 
 
     ASSERT_TRUE(any);
     ASSERT_TRUE(any);
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
-    ASSERT_TRUE(any.convert<double>());
-    ASSERT_FALSE(any.convert<char>());
+    ASSERT_TRUE(any.allow_cast<double>());
+    ASSERT_FALSE(any.allow_cast<char>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.cast<double>(), 42.);
     ASSERT_EQ(any.cast<double>(), 42.);
 
 
-    auto other = any.convert<int>();
+    auto other = any.allow_cast<int>();
 
 
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.type(), entt::resolve<double>());
     ASSERT_EQ(any.cast<double>(), 42.);
     ASSERT_EQ(any.cast<double>(), 42.);
@@ -638,11 +638,11 @@ TEST_F(MetaAny, UnmanageableType) {
     ASSERT_EQ(any.try_cast<int>(), nullptr);
     ASSERT_EQ(any.try_cast<int>(), nullptr);
     ASSERT_NE(any.try_cast<unmanageable_t>(), nullptr);
     ASSERT_NE(any.try_cast<unmanageable_t>(), nullptr);
 
 
-    ASSERT_TRUE(any.convert<unmanageable_t>());
-    ASSERT_FALSE(any.convert<int>());
+    ASSERT_TRUE(any.allow_cast<unmanageable_t>());
+    ASSERT_FALSE(any.allow_cast<int>());
 
 
-    ASSERT_TRUE(std::as_const(any).convert<unmanageable_t>());
-    ASSERT_FALSE(std::as_const(any).convert<int>());
+    ASSERT_TRUE(std::as_const(any).allow_cast<unmanageable_t>());
+    ASSERT_FALSE(std::as_const(any).allow_cast<int>());
 }
 }
 
 
 TEST_F(MetaAny, Invoke) {
 TEST_F(MetaAny, Invoke) {

+ 2 - 2
test/entt/meta/meta_type.cpp

@@ -583,8 +583,8 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
     entt::meta_any any{42.};
     entt::meta_any any{42.};
 
 
     ASSERT_TRUE(any);
     ASSERT_TRUE(any);
-    ASSERT_FALSE(any.convert<int>());
-    ASSERT_TRUE(any.convert<float>());
+    ASSERT_FALSE(any.allow_cast<int>());
+    ASSERT_TRUE(any.allow_cast<float>());
 
 
     ASSERT_FALSE(entt::resolve("derived"_hs));
     ASSERT_FALSE(entt::resolve("derived"_hs));
     ASSERT_TRUE(entt::resolve("double"_hs));
     ASSERT_TRUE(entt::resolve("double"_hs));

+ 1 - 1
test/lib/meta/main.cpp

@@ -35,7 +35,7 @@ TEST(Lib, Meta) {
     ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
     ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
 
 
     ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
     ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
-    ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).convert<double>());
+    ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).allow_cast<double>());
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
 
 

+ 1 - 1
test/lib/meta_plugin/main.cpp

@@ -36,7 +36,7 @@ TEST(Lib, Meta) {
     ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
     ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
 
 
     ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
     ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
-    ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).convert<double>());
+    ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).allow_cast<double>());
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
 
 

+ 1 - 1
test/lib/meta_plugin_std/main.cpp

@@ -36,7 +36,7 @@ TEST(Lib, Meta) {
     ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
     ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
 
 
     ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
     ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
-    ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).convert<double>());
+    ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).allow_cast<double>());
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);