Explorar el Código

any/meta:
* added alias constructor to any
* added alias constructor to meta_any
* added alias constructor to poly
* added support for const containers, const deref operator and const views to meta_any

Michele Caini hace 5 años
padre
commit
aa979b2046

+ 12 - 5
docs/md/core.md

@@ -267,15 +267,22 @@ A particularly interesting feature of this class is that it can also be used as
 an opaque container for const and non-const references:
 
 ```cpp
-int value;
+int value = 42;
+
+// reference construction
 entt::any any{std::ref(value)};
 entt::any cany{std::cref(value)};
+
+// alias construction
+int value = 42;
+entt::any in_place{std::in_place_type<int &>, &value};
 ```
 
-In other words, whenever `any` intercepts a `reference_wrapper`, it acts as a
-pointer to the original instance rather than making a copy of it or moving it
-internally. The _contained_ object is never destroyed and users must ensure that
-its lifetime exceeds that of the container.<br/>
+In other words, whenever `any` intercepts a `reference_wrapper` or is explicitly
+told that users want to construct an alias, it acts as a pointer to the original
+instance rather than making a copy of it or moving it internally. The contained
+object is never destroyed and users must ensure that its lifetime exceeds that
+of the container.<br/>
 Similarly, it's possible to create non-owning copies of `any` from an existing
 object:
 

+ 8 - 6
src/entt/core/any.hpp

@@ -128,8 +128,7 @@ class any {
 public:
     /*! @brief Default constructor. */
     any() ENTT_NOEXCEPT
-        : vtable{&basic_vtable<void>},
-          instance{}
+        : any{std::in_place_type<void>}
     {}
 
     /**
@@ -144,7 +143,11 @@ public:
           instance{}
     {
         if constexpr(!std::is_void_v<Type>) {
-            if constexpr(in_situ<Type>) {
+            if constexpr(std::is_lvalue_reference_v<Type>) {
+                static_assert(sizeof...(Args) == 1u && (std::is_pointer_v<std::remove_reference_t<Args>> && ...));
+                ENTT_ASSERT(((args != nullptr) && ...));
+                instance = (args, ...);
+            } else if constexpr(in_situ<Type>) {
                 new (&storage) Type{std::forward<Args>(args)...};
             } else {
                 instance = new Type{std::forward<Args>(args)...};
@@ -159,8 +162,7 @@ public:
      */
     template<typename Type>
     any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
-        : vtable{&basic_vtable<Type &>},
-          instance{&value.get()}
+        : any{std::in_place_type<Type &>, &value.get()}
     {}
 
     /**
@@ -316,7 +318,7 @@ private:
  */
 template<typename Type>
 Type any_cast(const any &data) ENTT_NOEXCEPT {
-    auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
+    const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
     ENTT_ASSERT(instance);
     return static_cast<Type>(*instance);
 }

+ 186 - 34
src/entt/meta/container.hpp

@@ -5,11 +5,13 @@
 #include <array>
 #include <map>
 #include <set>
+#include <type_traits>
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
 #include <vector>
 #include "../config/config.h"
+#include "../core/type_traits.hpp"
 #include "type_traits.hpp"
 
 
@@ -22,7 +24,7 @@ namespace entt {
  * @tparam Trait Traits associated with the underlying container.
  */
 template<typename Container, template<typename> class... Trait>
-struct container_traits: public Trait<Container>... {};
+struct meta_container_traits: public Trait<Container>... {};
 
 
 /**
@@ -32,7 +34,7 @@ struct container_traits: public Trait<Container>... {};
 template<typename Container>
 struct basic_container {
     /*! @brief Iterator type of the container. */
-    using iterator = typename Container::iterator;
+    using iterator = std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>;
     /*! @brief Unsigned integer type. */
     using size_type = typename Container::size_type;
     /*! @brief Value type of the container. */
@@ -77,13 +79,13 @@ struct basic_associative_container {
     using key_type = typename Container::key_type;
 
     /**
-     * @brief Returns an iterator to the element with key equivalent to the given
-     * one, if any.
+     * @brief Returns an iterator to the element with key equivalent to the
+     * given one, if any.
      * @param cont The container in which to search for the element.
      * @param key The key of the element to search.
      * @return An iterator to the element with the given key, if any.
      */
-    [[nodiscard]] static typename Container::iterator find(Container &cont, const key_type &key) {
+    [[nodiscard]] static std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator> find(Container &cont, const key_type &key) {
         return cont.find(key);
     }
 };
@@ -100,8 +102,12 @@ struct basic_dynamic_container {
      * @param cont The container for which to clear the content.
      * @return True in case of success, false otherwise.
      */
-    [[nodiscard]] static bool clear(Container &cont) {
-        return cont.clear(), true;
+    [[nodiscard]] static bool clear([[maybe_unused]] Container &cont) {
+        if constexpr(std::is_const_v<Container>) {
+            return false;
+        } else {
+            return cont.clear(), true;
+        }
     }
 };
 
@@ -118,9 +124,13 @@ struct basic_dynamic_associative_container {
      * @param key The element to remove.
      * @return A bool denoting whether the removal took place.
      */
-    [[nodiscard]] static bool erase(Container &cont, const typename Container::key_type &key) {
-        const auto sz = cont.size();
-        return cont.erase(key) != sz;
+    [[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
+        if constexpr(std::is_const_v<Container>) {
+            return false;
+        } else {
+            const auto sz = cont.size();
+            return cont.erase(key) != sz;
+        }
     }
 };
 
@@ -132,13 +142,13 @@ struct basic_dynamic_associative_container {
 template<typename Container>
 struct basic_sequence_container {
     /**
-     * @brief Returns a reference to the element at the specified location of the
-     * given container (no bounds checking is performed).
+     * @brief Returns a reference to the element at the specified location of
+     * the given container (no bounds checking is performed).
      * @param cont The container from which to get the element.
      * @param pos The position of the element to return.
      * @return A reference to the requested element.
      */
-    [[nodiscard]] static typename Container::value_type & get(Container &cont, typename Container::size_type pos) {
+    [[nodiscard]] static constness_as_t<typename Container::value_type, Container> & get(Container &cont, typename Container::size_type pos) {
         return cont[pos];
     }
 };
@@ -156,8 +166,12 @@ struct dynamic_associative_key_only_container {
      * @param key The element to insert.
      * @return A bool denoting whether the insertion took place.
      */
-    [[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key) {
-        return cont.insert(key).second;
+    [[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
+        if constexpr(std::is_const_v<Container>) {
+            return false;
+        } else {
+            return cont.insert(key).second;
+        }
     }
 };
 
@@ -175,8 +189,12 @@ struct dynamic_associative_key_value_container {
      * @param value The value of the element to insert.
      * @return A bool denoting whether the insertion took place.
      */
-    [[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key, const typename Container::mapped_type &value) {
-        return cont.insert(std::make_pair(key, value)).second;
+    [[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) {
+        if constexpr(std::is_const_v<Container>) {
+            return false;
+        } else {
+            return cont.insert(std::make_pair(key, value)).second;
+        }
     }
 };
 
@@ -188,37 +206,54 @@ struct dynamic_associative_key_value_container {
 template<typename Container>
 struct dynamic_sequence_container {
     /**
-     * @brief Resizes the given container to contain the given number of elements.
+     * @brief Resizes the given container to contain the given number of
+     * elements.
      * @param cont The container to resize.
      * @param sz The new size of the container.
      * @return True in case of success, false otherwise.
      */
-    [[nodiscard]] static bool resize(Container &cont, typename Container::size_type sz) {
-        return (cont.resize(sz), true);
+    [[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) {
+        if constexpr(std::is_const_v<Container>) {
+            return false;
+        } else {
+            return cont.resize(sz), true;
+        }
     }
 
     /**
-     * @brief Inserts an element at the specified location of the given container.
+     * @brief Inserts an element at the specified location of the given
+     * container.
      * @param cont The container into which to insert the element.
      * @param it Iterator before which the element will be inserted.
      * @param value Element value to insert.
      * @return A pair consisting of an iterator to the inserted element (in case
      * of success) and a bool denoting whether the insertion took place.
      */
-    [[nodiscard]] static std::pair<typename Container::iterator, bool> insert(Container &cont, typename Container::iterator it, const typename Container::value_type &value) {
-        return { cont.insert(it, value), true };
+    [[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
+    insert([[maybe_unused]] Container &cont, [[maybe_unused]] std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator> it, [[maybe_unused]] const typename Container::value_type &value) {
+        if constexpr(std::is_const_v<Container>) {
+            return { {}, false };
+        } else {
+            return { cont.insert(it, value), true };
+        }
     }
 
     /**
-     * @brief Removes the element at the specified location from the given container.
+     * @brief Removes the element at the specified location from the given
+     * container.
      * @param cont The container from which to remove the element.
      * @param it Iterator to the element to remove.
      * @return A pair consisting of an iterator following the last removed
      * element (in case of success) and a bool denoting whether the insertion
      * took place.
      */
-    [[nodiscard]] static std::pair<typename Container::iterator, bool> erase(Container &cont, typename Container::iterator it) {
-        return { cont.erase(it), true };
+    [[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
+    erase([[maybe_unused]] Container &cont, [[maybe_unused]] std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator> it) {
+        if constexpr(std::is_const_v<Container>) {
+            return { {}, false };
+        } else {
+            return { cont.erase(it), true };
+        }
     }
 };
 
@@ -250,7 +285,8 @@ struct fixed_sequence_container {
      * @return A pair consisting of an invalid iterator and a false value to
      * indicate failure in all cases.
      */
-    [[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::iterator, const typename Container::value_type &) {
+    [[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
+    insert(const Container &, std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, const typename Container::value_type &) {
         return { {}, false };
     }
 
@@ -259,7 +295,8 @@ struct fixed_sequence_container {
      * @return A pair consisting of an invalid iterator and a false value to
      * indicate failure in all cases.
      */
-    [[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::iterator) {
+    [[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
+    erase(const Container &, std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>) {
         return { {}, false };
     }
 };
@@ -272,7 +309,7 @@ struct fixed_sequence_container {
  */
 template<typename Type, typename... Args>
 struct meta_sequence_container_traits<std::vector<Type, Args...>>
-        : container_traits<
+        : meta_container_traits<
               std::vector<Type, Args...>,
               basic_container,
               basic_dynamic_container,
@@ -282,6 +319,23 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
 {};
 
 
+/**
+ * @brief Meta sequence container traits for const `std::vector`s of any type.
+ * @tparam Type The type of elements.
+ * @tparam Args Other arguments.
+ */
+template<typename Type, typename... Args>
+struct meta_sequence_container_traits<const std::vector<Type, Args...>>
+        : meta_container_traits<
+              const std::vector<Type, Args...>,
+              basic_container,
+              basic_dynamic_container,
+              basic_sequence_container,
+              dynamic_sequence_container
+          >
+{};
+
+
 /**
  * @brief Meta sequence container traits for `std::array`s of any type.
  * @tparam Type The type of elements.
@@ -289,7 +343,7 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
  */
 template<typename Type, auto N>
 struct meta_sequence_container_traits<std::array<Type, N>>
-        : container_traits<
+        : meta_container_traits<
               std::array<Type, N>,
               basic_container,
               basic_sequence_container,
@@ -298,6 +352,22 @@ struct meta_sequence_container_traits<std::array<Type, N>>
 {};
 
 
+/**
+ * @brief Meta sequence container traits for const `std::array`s of any type.
+ * @tparam Type The type of elements.
+ * @tparam N The number of elements.
+ */
+template<typename Type, auto N>
+struct meta_sequence_container_traits<const std::array<Type, N>>
+        : meta_container_traits<
+              const std::array<Type, N>,
+              basic_container,
+              basic_sequence_container,
+              fixed_sequence_container
+          >
+{};
+
+
 /**
  * @brief Meta associative container traits for `std::map`s of any type.
  * @tparam Key The key type of elements.
@@ -306,7 +376,7 @@ struct meta_sequence_container_traits<std::array<Type, N>>
  */
 template<typename Key, typename Value, typename... Args>
 struct meta_associative_container_traits<std::map<Key, Value, Args...>>
-        : container_traits<
+        : meta_container_traits<
               std::map<Key, Value, Args...>,
               basic_container,
               basic_associative_container,
@@ -320,6 +390,28 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
 };
 
 
+/**
+ * @brief Meta associative container traits for const `std::map`s of any type.
+ * @tparam Key The key type of elements.
+ * @tparam Value The value type of elements.
+ * @tparam Args Other arguments.
+ */
+template<typename Key, typename Value, typename... Args>
+struct meta_associative_container_traits<const std::map<Key, Value, Args...>>
+        : meta_container_traits<
+              const 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. */
+    using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
+};
+
+
 /**
  * @brief Meta associative container traits for `std::unordered_map`s of any
  * type.
@@ -329,7 +421,7 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
  */
 template<typename Key, typename Value, typename... Args>
 struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
-        : container_traits<
+        : meta_container_traits<
               std::unordered_map<Key, Value, Args...>,
               basic_container,
               basic_associative_container,
@@ -343,6 +435,29 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
 };
 
 
+/**
+ * @brief Meta associative container traits for const `std::unordered_map`s of
+ * any type.
+ * @tparam Key The key type of elements.
+ * @tparam Value The value type of elements.
+ * @tparam Args Other arguments.
+ */
+template<typename Key, typename Value, typename... Args>
+struct meta_associative_container_traits<const std::unordered_map<Key, Value, Args...>>
+        : meta_container_traits<
+              const 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. */
+    using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
+};
+
+
 /**
  * @brief Meta associative container traits for `std::set`s of any type.
  * @tparam Key The type of elements.
@@ -350,7 +465,7 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
  */
 template<typename Key, typename... Args>
 struct meta_associative_container_traits<std::set<Key, Args...>>
-        : container_traits<
+        : meta_container_traits<
               std::set<Key, Args...>,
               basic_container,
               basic_associative_container,
@@ -361,6 +476,24 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
 {};
 
 
+/**
+ * @brief Meta associative container traits for const `std::set`s of any type.
+ * @tparam Key The type of elements.
+ * @tparam Args Other arguments.
+ */
+template<typename Key, typename... Args>
+struct meta_associative_container_traits<const std::set<Key, Args...>>
+        : meta_container_traits<
+              const std::set<Key, Args...>,
+              basic_container,
+              basic_associative_container,
+              basic_dynamic_container,
+              basic_dynamic_associative_container,
+              dynamic_associative_key_only_container
+          >
+{};
+
+
 /**
  * @brief Meta associative container traits for `std::unordered_set`s of any
  * type.
@@ -369,7 +502,7 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
  */
 template<typename Key, typename... Args>
 struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
-        : container_traits<
+        : meta_container_traits<
               std::unordered_set<Key, Args...>,
               basic_container,
               basic_associative_container,
@@ -380,6 +513,25 @@ struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
 {};
 
 
+/**
+ * @brief Meta associative container traits for const `std::unordered_set`s of
+ * any type.
+ * @tparam Key The type of elements.
+ * @tparam Args Other arguments.
+ */
+template<typename Key, typename... Args>
+struct meta_associative_container_traits<const std::unordered_set<Key, Args...>>
+        : meta_container_traits<
+              const std::unordered_set<Key, Args...>,
+              basic_container,
+              basic_associative_container,
+              basic_dynamic_container,
+              basic_dynamic_associative_container,
+              dynamic_associative_key_only_container
+          >
+{};
+
+
 }
 
 

+ 0 - 10
src/entt/meta/internal.hpp

@@ -118,7 +118,6 @@ struct meta_type_node {
     const bool is_associative_container;
     const size_type rank;
     size_type(* const extent)(size_type);
-    bool(* const compare)(const void *, const void *);
     meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
     meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
     meta_base_node *base{nullptr};
@@ -219,14 +218,6 @@ template<typename Type>
 class ENTT_API meta_node {
     static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
 
-    [[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
-        if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
-            return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
-        } else {
-            return lhs == rhs;
-        }
-    }
-
     template<std::size_t... Index>
     [[nodiscard]] static auto extent(meta_type_node::size_type dim, std::index_sequence<Index...>) {
         meta_type_node::size_type ext{};
@@ -260,7 +251,6 @@ public:
             [](meta_type_node::size_type dim) {
                 return extent(dim, std::make_index_sequence<std::rank_v<Type>>{});
             },
-            &compare, // workaround for an issue with VS2017
             &meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
             &meta_node<std::remove_cv_t<std::remove_extent_t<Type>>>::resolve
         };

+ 150 - 118
src/entt/meta/meta.hpp

@@ -41,17 +41,15 @@ public:
     using iterator = meta_iterator;
 
     /*! @brief Default constructor. */
-    meta_sequence_container() ENTT_NOEXCEPT
-        : instance{nullptr}
-    {}
+    meta_sequence_container() ENTT_NOEXCEPT = default;
 
     /**
      * @brief Construct a proxy object for sequence containers.
      * @tparam Type Type of container to wrap.
-     * @param container The container to wrap.
+     * @param instance The container to wrap.
      */
     template<typename Type>
-    meta_sequence_container(Type *container) ENTT_NOEXCEPT
+    meta_sequence_container(Type &instance) ENTT_NOEXCEPT
         : value_type_fn{&meta_sequence_container_proxy<Type>::value_type},
           size_fn{&meta_sequence_container_proxy<Type>::size},
           resize_fn{&meta_sequence_container_proxy<Type>::resize},
@@ -61,12 +59,12 @@ public:
           insert_fn{&meta_sequence_container_proxy<Type>::insert},
           erase_fn{&meta_sequence_container_proxy<Type>::erase},
           get_fn{&meta_sequence_container_proxy<Type>::get},
-          instance{container}
+          storage{std::reference_wrapper{instance}}
     {}
 
     [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT;
     [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT;
-    inline bool resize(size_type) const;
+    inline bool resize(size_type);
     inline bool clear();
     [[nodiscard]] inline iterator begin();
     [[nodiscard]] inline iterator end();
@@ -77,15 +75,15 @@ public:
 
 private:
     meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr;
-    size_type(* size_fn)(const void *) ENTT_NOEXCEPT = nullptr;
-    bool(* resize_fn)(void *, size_type) = nullptr;
-    bool(* clear_fn)(void *) = nullptr;
-    iterator(* begin_fn)(void *) = nullptr;
-    iterator(* end_fn)(void *) = nullptr;
-    std::pair<iterator, bool>(* insert_fn)(void *, iterator, meta_any) = nullptr;
-    std::pair<iterator, bool>(* erase_fn)(void *, iterator) = nullptr;
-    meta_any(* get_fn)(void *, size_type) = nullptr;
-    void *instance{};
+    size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr;
+    bool(* resize_fn)(any &, size_type) = nullptr;
+    bool(* clear_fn)(any &) = nullptr;
+    iterator(* begin_fn)(any &) = nullptr;
+    iterator(* end_fn)(any &) = nullptr;
+    std::pair<iterator, bool>(* insert_fn)(any &, iterator, meta_any &) = nullptr;
+    std::pair<iterator, bool>(* erase_fn)(any &, iterator) = nullptr;
+    meta_any(* get_fn)(any &, size_type) = nullptr;
+    any storage{};
 };
 
 
@@ -103,17 +101,15 @@ public:
     using iterator = meta_iterator;
 
     /*! @brief Default constructor. */
-    meta_associative_container() ENTT_NOEXCEPT
-        : instance{nullptr}
-    {}
+    meta_associative_container() ENTT_NOEXCEPT = default;
 
     /**
      * @brief Construct a proxy object for associative containers.
      * @tparam Type Type of container to wrap.
-     * @param container The container to wrap.
+     * @param instance The container to wrap.
      */
     template<typename Type>
-    meta_associative_container(Type *container) ENTT_NOEXCEPT
+    meta_associative_container(Type &instance) ENTT_NOEXCEPT
         : key_only_container{is_key_only_meta_associative_container_v<Type>},
           key_type_fn{&meta_associative_container_proxy<Type>::key_type},
           mapped_type_fn{&meta_associative_container_proxy<Type>::mapped_type},
@@ -125,7 +121,7 @@ public:
           insert_fn{&meta_associative_container_proxy<Type>::insert},
           erase_fn{&meta_associative_container_proxy<Type>::erase},
           find_fn{&meta_associative_container_proxy<Type>::find},
-          instance{container}
+          storage{std::reference_wrapper{instance}}
     {}
 
     [[nodiscard]] inline bool key_only() const ENTT_NOEXCEPT;
@@ -146,41 +142,58 @@ private:
     meta_type(* key_type_fn)() ENTT_NOEXCEPT = nullptr;
     meta_type(* mapped_type_fn)() ENTT_NOEXCEPT = nullptr;
     meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr;
-    size_type(* size_fn)(const void *) ENTT_NOEXCEPT = nullptr;
-    bool(* clear_fn)(void *) = nullptr;
-    iterator(* begin_fn)(void *) = nullptr;
-    iterator(* end_fn)(void *) = nullptr;
-    bool(* insert_fn)(void *, meta_any, meta_any) = nullptr;
-    bool(* erase_fn)(void *, meta_any) = nullptr;
-    iterator(* find_fn)(void *, meta_any) = nullptr;
-    void *instance{};
+    size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr;
+    bool(* clear_fn)(any &) = nullptr;
+    iterator(* begin_fn)(any &) = nullptr;
+    iterator(* end_fn)(any &) = nullptr;
+    bool(* insert_fn)(any &, meta_any &, meta_any &) = nullptr;
+    bool(* erase_fn)(any &, meta_any &) = nullptr;
+    iterator(* find_fn)(any &, meta_any &) = nullptr;
+    any storage{};
 };
 
 
 /*! @brief Opaque wrapper for values of any type. */
 class meta_any {
-    enum class operation { DEREF, SEQ, ASSOC };
+    enum class operation { DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC };
 
-    using vtable_type = void(const operation, meta_any &, void *);
+    using vtable_type = void(const operation, const any &, void *);
 
     template<typename Type>
-    static void basic_vtable(const operation op, [[maybe_unused]] meta_any &from, [[maybe_unused]] void *to) {
+    static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) {
         switch(op) {
         case operation::DEREF:
             if constexpr(is_meta_pointer_like_v<Type>) {
-                if(auto ptr = from.cast<Type>(); ptr) {
-                    *static_cast<meta_any *>(to) = std::reference_wrapper{*ptr};
-                }
+                *static_cast<meta_any *>(to) = std::ref(*any_cast<const Type>(from));
+            }
+            break;
+        case operation::CDEREF:
+            if constexpr(is_meta_pointer_like_v<Type>) {
+                *static_cast<meta_any *>(to) = std::cref(*any_cast<const Type>(from));
             }
             break;
         case operation::SEQ:
             if constexpr(has_meta_sequence_container_traits_v<Type>) {
-                *static_cast<meta_sequence_container *>(to) = static_cast<Type *>(from.data());
+                if(auto *instance = any_cast<Type>(&const_cast<any &>(from)); instance) {
+                    return *static_cast<meta_sequence_container *>(to) = *instance, void();
+                }
+            }
+            [[fallthrough]];
+        case operation::CSEQ:
+            if constexpr(has_meta_sequence_container_traits_v<Type>) {
+                *static_cast<meta_sequence_container *>(to) = any_cast<const Type &>(from);
             }
             break;
         case operation::ASSOC:
             if constexpr(has_meta_associative_container_traits_v<Type>) {
-                *static_cast<meta_associative_container *>(to) = static_cast<Type *>(from.data());
+                if(auto *instance = any_cast<Type>(&const_cast<any &>(from)); instance) {
+                    return *static_cast<meta_associative_container *>(to) = *instance, void();
+                }
+            }
+            [[fallthrough]];
+        case operation::CASSOC:
+            if constexpr(has_meta_associative_container_traits_v<Type>) {
+                *static_cast<meta_associative_container *>(to) = any_cast<const Type &>(from);
             }
             break;
         }
@@ -203,8 +216,8 @@ public:
     template<typename Type, typename... Args>
     explicit meta_any(std::in_place_type_t<Type>, Args &&... args)
         : storage(std::in_place_type<Type>, std::forward<Args>(args)...),
-          vtable{&basic_vtable<Type>},
-          node{internal::meta_info<Type>::resolve()}
+          vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
+          node{internal::meta_info<std::remove_const_t<std::remove_reference_t<Type>>>::resolve()}
     {}
 
     /**
@@ -214,9 +227,7 @@ public:
      */
     template<typename Type>
     meta_any(std::reference_wrapper<Type> value)
-        : storage{value},
-          vtable{&basic_vtable<Type>},
-          node{internal::meta_info<Type>::resolve()}
+        : meta_any{std::in_place_type<Type &>, &value.get()}
     {}
 
     /**
@@ -443,7 +454,14 @@ public:
      */
     [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT {
         meta_sequence_container proxy;
-        vtable(operation::SEQ, *this, &proxy);
+        vtable(operation::SEQ, storage, &proxy);
+        return proxy;
+    }
+
+    /*! @copydoc as_sequence_container */
+    [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT {
+        meta_sequence_container proxy;
+        vtable(operation::CSEQ, storage, &proxy);
         return proxy;
     }
 
@@ -453,7 +471,14 @@ public:
      */
     [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT {
         meta_associative_container proxy;
-        vtable(operation::ASSOC, *this, &proxy);
+        vtable(operation::ASSOC, storage, &proxy);
+        return proxy;
+    }
+
+    /*! @copydoc as_associative_container */
+    [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT {
+        meta_associative_container proxy;
+        vtable(operation::CASSOC, storage, &proxy);
         return proxy;
     }
 
@@ -464,7 +489,14 @@ public:
      */
     [[nodiscard]] meta_any operator*() ENTT_NOEXCEPT {
         meta_any any{};
-        vtable(operation::DEREF, *this, &any);
+        vtable(operation::DEREF, storage, &any);
+        return any;
+    }
+
+    /*! @copydoc operator* */
+    [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT {
+        meta_any any{};
+        vtable(operation::CDEREF, storage, &any);
         return any;
     }
 
@@ -482,7 +514,7 @@ public:
      * @return False if the two objects differ in their content, true otherwise.
      */
     [[nodiscard]] bool operator==(const meta_any &other) const {
-        return (!node && !other.node) || (node && other.node && node->info == other.node->info && node->compare(storage.data(), other.storage.data()));
+        return (node == other.node) && (storage == other.storage);
     }
 
     /**
@@ -1671,13 +1703,13 @@ class meta_sequence_container::meta_iterator {
     friend class meta_sequence_container;
 
     template<typename It>
-    static void incr(meta_any any) {
-        ++any.cast<It &>();
+    static void incr(any &ref) {
+        ++any_cast<It &>(ref);
     }
 
     template<typename It>
-    [[nodiscard]] static meta_any deref(meta_any any) {
-        return std::reference_wrapper{*any.cast<const It &>()};
+    [[nodiscard]] static meta_any deref(const any &ref) {
+        return std::reference_wrapper{*any_cast<const It &>(ref)};
     }
 
 public:
@@ -1709,7 +1741,7 @@ public:
 
     /*! @brief Pre-increment operator. @return This iterator. */
     meta_iterator & operator++() ENTT_NOEXCEPT {
-        return next_fn(as_ref(handle)), *this;
+        return next_fn(handle), *this;
     }
 
     /*! @brief Post-increment operator. @return This iterator. */
@@ -1743,7 +1775,7 @@ public:
      * @return The element to which the meta pointer points.
      */
     [[nodiscard]] reference operator*() const {
-        return get_fn(as_ref(handle));
+        return get_fn(handle);
     }
 
     /**
@@ -1755,9 +1787,9 @@ public:
     }
 
 private:
-    void(* next_fn)(meta_any);
-    meta_any(* get_fn)(meta_any);
-    meta_any handle;
+    void(* next_fn)(any &);
+    meta_any(* get_fn)(const any &);
+    any handle;
 };
 
 
@@ -1769,42 +1801,42 @@ struct meta_sequence_container::meta_sequence_container_proxy {
         return internal::meta_info<typename traits_type::value_type>::resolve();
     }
 
-    [[nodiscard]] static size_type size(const void *container) ENTT_NOEXCEPT {
-        return traits_type::size(*static_cast<const Type *>(container));
+    [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
+        return traits_type::size(any_cast<const Type &>(container));
     }
 
-    [[nodiscard]] static bool resize(void *container, size_type sz) {
-        return traits_type::resize(*static_cast<Type *>(container), sz);
+    [[nodiscard]] static bool resize(any &container, size_type sz) {
+        return traits_type::resize(any_cast<Type &>(container), sz);
     }
 
-    [[nodiscard]] static bool clear(void *container) {
-        return traits_type::clear(*static_cast<Type *>(container));
+    [[nodiscard]] static bool clear(any &container) {
+        return traits_type::clear(any_cast<Type &>(container));
     }
 
-    [[nodiscard]] static iterator begin(void *container) {
-        return iterator{traits_type::begin(*static_cast<Type *>(container))};
+    [[nodiscard]] static iterator begin(any &container) {
+        return iterator{traits_type::begin(any_cast<Type &>(container))};
     }
 
-    [[nodiscard]] static iterator end(void *container) {
-        return iterator{traits_type::end(*static_cast<Type *>(container))};
+    [[nodiscard]] static iterator end(any &container) {
+        return iterator{traits_type::end(any_cast<Type &>(container))};
     }
 
-    [[nodiscard]] static std::pair<iterator, bool> insert(void *container, iterator it, meta_any value) {
+    [[nodiscard]] static std::pair<iterator, bool> insert(any &container, iterator it, meta_any &value) {
         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 &>());
+            auto ret = traits_type::insert(any_cast<Type &>(container), any_cast<const typename traits_type::iterator &>(it.handle), value.cast<const typename traits_type::value_type &>());
             return { iterator{std::move(ret.first)}, ret.second };
         }
 
         return {};
     }
 
-    [[nodiscard]] static std::pair<iterator, bool> erase(void *container, iterator it) {
-        auto ret = traits_type::erase(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>());
+    [[nodiscard]] static std::pair<iterator, bool> erase(any &container, iterator it) {
+        auto ret = traits_type::erase(any_cast<Type &>(container), any_cast<const typename traits_type::iterator &>(it.handle));
         return { iterator{std::move(ret.first)}, ret.second };
     }
 
-    [[nodiscard]] static meta_any get(void *container, size_type pos) {
-        return std::reference_wrapper{traits_type::get(*static_cast<Type *>(container), pos)};
+    [[nodiscard]] static meta_any get(any &container, size_type pos) {
+        return std::reference_wrapper{traits_type::get(any_cast<Type &>(container), pos)};
     }
 };
 
@@ -1823,7 +1855,7 @@ struct meta_sequence_container::meta_sequence_container_proxy {
  * @return The size of the wrapped container.
  */
 [[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const ENTT_NOEXCEPT {
-    return size_fn(instance);
+    return size_fn(storage);
 }
 
 
@@ -1832,8 +1864,8 @@ struct meta_sequence_container::meta_sequence_container_proxy {
  * @param sz The new size of the container.
  * @return True in case of success, false otherwise.
  */
-inline bool meta_sequence_container::resize(size_type sz) const {
-    return resize_fn(instance, sz);
+inline bool meta_sequence_container::resize(size_type sz) {
+    return resize_fn(storage, sz);
 }
 
 
@@ -1842,7 +1874,7 @@ inline bool meta_sequence_container::resize(size_type sz) const {
  * @return True in case of success, false otherwise.
  */
 inline bool meta_sequence_container::clear() {
-    return clear_fn(instance);
+    return clear_fn(storage);
 }
 
 
@@ -1851,7 +1883,7 @@ inline bool meta_sequence_container::clear() {
  * @return A meta iterator to the first element of the wrapped container.
  */
 [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
-    return begin_fn(instance);
+    return begin_fn(storage);
 }
 
 
@@ -1862,7 +1894,7 @@ inline bool meta_sequence_container::clear() {
  * container.
  */
 [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
-    return end_fn(instance);
+    return end_fn(storage);
 }
 
 
@@ -1874,7 +1906,7 @@ inline bool meta_sequence_container::clear() {
  * case of success) and a bool denoting whether the insertion took place.
  */
 inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_container::insert(iterator it, meta_any value) {
-    return insert_fn(instance, it, as_ref(value));
+    return insert_fn(storage, it, value);
 }
 
 
@@ -1886,7 +1918,7 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
  * took place.
  */
 inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_container::erase(iterator it) {
-    return erase_fn(instance, it);
+    return erase_fn(storage, it);
 }
 
 
@@ -1897,7 +1929,7 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
  * @return A reference to the requested element properly wrapped.
  */
 [[nodiscard]] inline meta_any meta_sequence_container::operator[](size_type pos) {
-    return get_fn(instance, pos);
+    return get_fn(storage, pos);
 }
 
 
@@ -1906,32 +1938,32 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
  * @return False if the proxy is invalid, true otherwise.
  */
 [[nodiscard]] inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT {
-    return (instance != nullptr);
+    return static_cast<bool>(storage);
 }
 
 
 /*! @brief Opaque iterator for meta associative containers. */
 class meta_associative_container::meta_iterator {
     template<typename It>
-    static void incr(meta_any any) {
-        ++any.cast<It &>();
+    static void incr(any &any) {
+        ++any_cast<It &>(any);
     }
 
     template<bool KeyOnly, typename It>
-    [[nodiscard]] static meta_any key(meta_any any) {
+    [[nodiscard]] static meta_any key(const any &ref) {
         if constexpr(KeyOnly) {
-            return *any.cast<const It &>();
+            return *any_cast<const It &>(ref);
         } else {
-            return any.cast<const It &>()->first;
+            return any_cast<const It &>(ref)->first;
         }
     }
 
     template<bool KeyOnly, typename It>
-    [[nodiscard]] static meta_any value([[maybe_unused]] meta_any any) {
+    [[nodiscard]] static meta_any value([[maybe_unused]] const any &ref) {
         if constexpr(KeyOnly) {
             return meta_any{};
         } else {
-            return std::reference_wrapper{any.cast<const It &>()->second};
+            return std::reference_wrapper{any_cast<const It &>(ref)->second};
         }
     }
 
@@ -1967,7 +1999,7 @@ public:
 
     /*! @brief Pre-increment operator. @return This iterator. */
     meta_iterator & operator++() ENTT_NOEXCEPT {
-        return next_fn(as_ref(handle)), *this;
+        return next_fn(handle), *this;
     }
 
     /*! @brief Post-increment operator. @return This iterator. */
@@ -2001,7 +2033,7 @@ public:
      * @return The element to which the meta pointer points.
      */
     [[nodiscard]] reference operator*() const {
-        return { key_fn(as_ref(handle)), value_fn(as_ref(handle)) };
+        return { key_fn(handle), value_fn(handle) };
     }
 
     /**
@@ -2013,10 +2045,10 @@ public:
     }
 
 private:
-    void(* next_fn)(meta_any);
-    meta_any(* key_fn)(meta_any);
-    meta_any(* value_fn)(meta_any);
-    meta_any handle;
+    void(* next_fn)(any &);
+    meta_any(* key_fn)(const any &);
+    meta_any(* value_fn)(const any &);
+    any handle;
 };
 
 
@@ -2040,29 +2072,29 @@ struct meta_associative_container::meta_associative_container_proxy {
         return internal::meta_info<typename traits_type::value_type>::resolve();
     }
 
-    [[nodiscard]] static size_type size(const void *container) ENTT_NOEXCEPT {
-        return traits_type::size(*static_cast<const Type *>(container));
+    [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
+        return traits_type::size(any_cast<const Type &>(container));
     }
 
-    [[nodiscard]] static bool clear(void *container) {
-        return traits_type::clear(*static_cast<Type *>(container));
+    [[nodiscard]] static bool clear(any &container) {
+        return traits_type::clear(any_cast<Type &>(container));
     }
 
-    [[nodiscard]] static iterator begin(void *container) {
-        return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::begin(*static_cast<Type *>(container))};
+    [[nodiscard]] static iterator begin(any &container) {
+        return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::begin(any_cast<Type &>(container))};
     }
 
-    [[nodiscard]] static iterator end(void *container) {
-        return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::end(*static_cast<Type *>(container))};
+    [[nodiscard]] static iterator end(any &container) {
+        return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::end(any_cast<Type &>(container))};
     }
 
-    [[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
+    [[nodiscard]] static bool insert(any &container, meta_any &key, meta_any &value) {
         if(key.allow_cast<const typename traits_type::key_type &>()) {
             if constexpr(is_key_only_meta_associative_container_v<Type>) {
-                return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
+                return traits_type::insert(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>());
             } else {
                 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 &>());
+                    return traits_type::insert(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>(), value.cast<const typename traits_type::mapped_type &>());
                 }
             }
         }
@@ -2070,17 +2102,17 @@ struct meta_associative_container::meta_associative_container_proxy {
         return false;
     }
 
-    [[nodiscard]] static bool erase(void *container, meta_any key) {
+    [[nodiscard]] static bool erase(any &container, meta_any &key) {
         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 traits_type::erase(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>());
         }
 
         return false;
     }
 
-    [[nodiscard]] static iterator find(void *container, meta_any key) {
+    [[nodiscard]] static iterator find(any &container, meta_any &key) {
         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 iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>())};
         }
 
         return {};
@@ -2124,25 +2156,25 @@ struct meta_associative_container::meta_associative_container_proxy {
 
 /*! @copydoc meta_sequence_container::size */
 [[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const ENTT_NOEXCEPT {
-    return size_fn(instance);
+    return size_fn(storage);
 }
 
 
 /*! @copydoc meta_sequence_container::clear */
 inline bool meta_associative_container::clear() {
-    return clear_fn(instance);
+    return clear_fn(storage);
 }
 
 
 /*! @copydoc meta_sequence_container::begin */
 [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() {
-    return begin_fn(instance);
+    return begin_fn(storage);
 }
 
 
 /*! @copydoc meta_sequence_container::end */
 [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() {
-    return end_fn(instance);
+    return end_fn(storage);
 }
 
 
@@ -2153,7 +2185,7 @@ inline bool meta_associative_container::clear() {
  * @return A bool denoting whether the insertion took place.
  */
 inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) {
-    return insert_fn(instance, as_ref(key), as_ref(value));
+    return insert_fn(storage, key, value);
 }
 
 
@@ -2163,7 +2195,7 @@ inline bool meta_associative_container::insert(meta_any key, meta_any value = {}
  * @return A bool denoting whether the removal took place.
  */
 inline bool meta_associative_container::erase(meta_any key) {
-    return erase_fn(instance, as_ref(key));
+    return erase_fn(storage, key);
 }
 
 
@@ -2174,7 +2206,7 @@ inline bool meta_associative_container::erase(meta_any key) {
  * @return An iterator to the element with the given key, if any.
  */
 [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) {
-    return find_fn(instance, as_ref(key));
+    return find_fn(storage, key);
 }
 
 
@@ -2183,7 +2215,7 @@ inline bool meta_associative_container::erase(meta_any key) {
  * @return False if the proxy is invalid, true otherwise.
  */
 [[nodiscard]] inline meta_associative_container::operator bool() const ENTT_NOEXCEPT {
-    return (instance != nullptr);
+    return static_cast<bool>(storage);
 }
 
 

+ 30 - 0
src/entt/meta/type_traits.hpp

@@ -33,6 +33,16 @@ template<typename Type, typename = void>
 struct has_meta_sequence_container_traits: std::false_type {};
 
 
+/**
+ * @brief TODO
+ * @tparam Type TODO
+ */
+template<typename Type>
+struct has_meta_sequence_container_traits<const Type>
+    : has_meta_sequence_container_traits<Type>
+{};
+
+
 /*! @copydoc has_meta_sequence_container_traits */
 template<typename Type>
 struct has_meta_sequence_container_traits<Type, std::void_t<typename meta_sequence_container_traits<Type>::value_type>>
@@ -57,6 +67,16 @@ template<typename, typename = void>
 struct has_meta_associative_container_traits: std::false_type {};
 
 
+/**
+ * @brief TODO
+ * @tparam Type TODO
+ */
+template<typename Type>
+struct has_meta_associative_container_traits<const Type>
+    : has_meta_associative_container_traits<Type>
+{};
+
+
 /*! @copydoc has_meta_associative_container_traits */
 template<typename Type>
 struct has_meta_associative_container_traits<Type, std::void_t<typename meta_associative_container_traits<Type>::key_type>>
@@ -81,6 +101,16 @@ template<typename, typename = void>
 struct is_key_only_meta_associative_container: std::true_type {};
 
 
+/**
+ * @brief TODO
+ * @tparam Type TODO
+ */
+template<typename Type>
+struct is_key_only_meta_associative_container<const Type>
+    : is_key_only_meta_associative_container<Type>
+{};
+
+
 /*! @copydoc is_key_only_meta_associative_container */
 template<typename Type>
 struct is_key_only_meta_associative_container<Type, std::void_t<typename meta_associative_container_traits<Type>::mapped_type>>

+ 5 - 4
src/entt/poly/poly.hpp

@@ -7,6 +7,7 @@
 #include <tuple>
 #include <type_traits>
 #include <utility>
+#include "../config/config.h"
 #include "../core/any.hpp"
 #include "../core/type_info.hpp"
 #include "../core/type_traits.hpp"
@@ -195,7 +196,7 @@ public:
     template<typename Type, typename... Args>
     explicit poly(std::in_place_type_t<Type>, Args &&... args)
         : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
-          vtable{poly_vtable<Concept>::template instance<Type>()}
+          vtable{poly_vtable<Concept>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()}
     {}
 
     /**
@@ -205,8 +206,7 @@ public:
      */
     template<typename Type>
     poly(std::reference_wrapper<Type> value)
-        : storage{value},
-          vtable{poly_vtable<Concept>::template instance<std::remove_const_t<Type>>()}
+        : poly{std::in_place_type<Type &>, &value.get()}
     {}
 
     /**
@@ -316,8 +316,9 @@ public:
      * @return A poly that shares a reference to an unmanaged object.
      */
     [[nodiscard]] friend poly as_ref(poly &other) ENTT_NOEXCEPT {
-        poly ref = as_ref(std::as_const(other));
+        poly ref;
         ref.storage = as_ref(other.storage);
+        ref.vtable = other.vtable;
         return ref;
     }
 

+ 166 - 0
test/entt/meta/meta_container.cpp

@@ -267,3 +267,169 @@ TEST_F(MetaContainer, StdSet) {
     ASSERT_TRUE(view.clear());
     ASSERT_EQ(view.size(), 0u);
 }
+
+TEST_F(MetaContainer, ConstSequenceContainer) {
+    std::vector<int> vec{};
+    entt::meta_any any{std::cref(vec)};
+
+    auto view = any.as_sequence_container();
+
+    ASSERT_TRUE(view);
+    ASSERT_EQ(view.value_type(), entt::resolve<int>());
+
+    ASSERT_EQ(view.size(), 0u);
+    ASSERT_EQ(view.begin(), view.end());
+    ASSERT_FALSE(view.resize(3u));
+    ASSERT_EQ(view.size(), 0u);
+    ASSERT_EQ(view.begin(), view.end());
+
+    vec.push_back(42);
+
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_NE(view.begin(), view.end());
+
+    ASSERT_DEATH(view[0].cast<int &>() = 2, ".*");
+    ASSERT_EQ(view[0].cast<const int &>(), 42);
+
+    auto it = view.begin();
+    auto ret = view.insert(it, 0);
+
+    ASSERT_FALSE(ret.second);
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_EQ((*it).cast<int>(), 42);
+    ASSERT_EQ(++it, view.end());
+
+    it = view.begin();
+    ret = view.erase(it);
+
+    ASSERT_FALSE(ret.second);
+    ASSERT_EQ(view.size(), 1u);
+
+    ASSERT_FALSE(view.clear());
+    ASSERT_EQ(view.size(), 1u);
+}
+
+TEST_F(MetaContainer, ConstKeyValueAssociativeContainer) {
+    std::map<int, char> map{};
+    entt::meta_any any{std::cref(map)};
+
+    auto view = any.as_associative_container();
+
+    ASSERT_TRUE(view);
+    ASSERT_FALSE(view.key_only());
+    ASSERT_EQ(view.key_type(), entt::resolve<int>());
+    ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
+    ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
+
+    ASSERT_EQ(view.size(), 0u);
+    ASSERT_EQ(view.begin(), view.end());
+
+    map[2] = 'c';
+
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_NE(view.begin(), view.end());
+
+    ASSERT_DEATH((*view.find(2)).second.cast<char &>() = 'a', ".*");
+    ASSERT_EQ((*view.find(2)).second.cast<const char &>(), 'c');
+
+    ASSERT_FALSE(view.insert(0, 'a'));
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_EQ(view.find(0), view.end());
+    ASSERT_EQ((*view.find(2)).second.cast<char>(), 'c');
+
+    ASSERT_FALSE(view.erase(2));
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_NE(view.find(2), view.end());
+
+    ASSERT_FALSE(view.clear());
+    ASSERT_EQ(view.size(), 1u);
+}
+
+TEST_F(MetaContainer, ConstKeyOnlyAssociativeContainer) {
+    std::set<int> set{};
+    entt::meta_any any{std::cref(set)};
+
+    auto view = any.as_associative_container();
+
+    ASSERT_TRUE(view);
+    ASSERT_TRUE(view.key_only());
+    ASSERT_EQ(view.key_type(), entt::resolve<int>());
+    ASSERT_EQ(view.mapped_type(), entt::meta_type{});
+    ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
+
+    ASSERT_EQ(view.size(), 0u);
+    ASSERT_EQ(view.begin(), view.end());
+
+    set.insert(2);
+
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_NE(view.begin(), view.end());
+
+    ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
+    ASSERT_EQ((*view.find(2)).first.cast<int &>(), 2);
+    ASSERT_EQ((*view.find(2)).first.cast<const int &>(), 2);
+
+    ASSERT_FALSE(view.insert(0));
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_EQ(view.find(0), view.end());
+    ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
+
+    ASSERT_FALSE(view.erase(2));
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_NE(view.find(2), view.end());
+
+    ASSERT_FALSE(view.clear());
+    ASSERT_EQ(view.size(), 1u);
+}
+
+TEST_F(MetaContainer, SequenceContainerConstMetaAny) {
+    auto test = [](const entt::meta_any any) {
+        auto view = any.as_sequence_container();
+
+        ASSERT_TRUE(view);
+        ASSERT_EQ(view.value_type(), entt::resolve<int>());
+        ASSERT_DEATH(view[0].cast<int &>() = 2, ".*");
+        ASSERT_EQ(view[0].cast<const int &>(), 42);
+    };
+
+    std::vector<int> vec{42};
+
+    test(vec);
+    test(std::ref(vec));
+    test(std::cref(vec));
+}
+
+TEST_F(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
+    auto test = [](const entt::meta_any any) {
+        auto view = any.as_associative_container();
+
+        ASSERT_TRUE(view);
+        ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
+        ASSERT_DEATH((*view.find(2)).second.cast<char &>() = 'a', ".*");
+        ASSERT_EQ((*view.find(2)).second.cast<const char &>(), 'c');
+    };
+
+    std::map<int, char> map{{2, 'c'}};
+
+    test(map);
+    test(std::ref(map));
+    test(std::cref(map));
+}
+
+TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
+    auto test = [](const entt::meta_any any) {
+        auto view = any.as_associative_container();
+
+        ASSERT_TRUE(view);
+        ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
+        ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
+        ASSERT_EQ((*view.find(2)).first.cast<int &>(), 2);
+        ASSERT_EQ((*view.find(2)).first.cast<const int &>(), 2);
+    };
+
+    std::set<int> set{2};
+
+    test(set);
+    test(std::ref(set));
+    test(std::cref(set));
+}

+ 21 - 0
test/entt/meta/meta_pointer.cpp

@@ -46,6 +46,27 @@ TEST(MetaPointerLike, DereferenceOperatorConstType) {
     ASSERT_EQ(deref.cast<const int &>(), 42);
 }
 
+TEST(MetaPointerLike, DereferenceOperatorConstAny) {
+    auto test = [](const entt::meta_any any) {
+        auto deref = *any;
+
+        ASSERT_TRUE(deref);
+        ASSERT_FALSE(deref.type().is_pointer());
+        ASSERT_FALSE(deref.type().is_pointer_like());
+        ASSERT_EQ(deref.type(), entt::resolve<int>());
+
+        ASSERT_EQ(deref.try_cast<int>(), nullptr);
+        ASSERT_NE(deref.try_cast<const int>(), nullptr);
+        ASSERT_DEATH(deref.cast<int &>() = 0, ".*");
+        ASSERT_EQ(deref.cast<const int &>(), 42);
+    };
+
+    int value = 42;
+
+    test(&value);
+    test(&std::as_const(value));
+}
+
 TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
     int value = 0;
     entt::meta_any any{&value};