Browse Source

test:
* support for pointer-like to const
* internal meta_range coverage
* fully tested meta_handle
* references as arguments for meta_ctor
* invoke const function on const reference for meta_func
* references as arguments for meta_func
* as_cref_t return type for meta_func
* setter and getter on const reference for meta_data
* as_cref_t getter for meta_data
* set by const and non-const reference for meta_data
* const invoke for meta_any
* const get for meta_any
* aob

Michele Caini 5 years ago
parent
commit
bc415242f2

+ 4 - 6
src/entt/meta/factory.hpp

@@ -82,8 +82,6 @@ template<typename Type, typename... Args, std::size_t... Index>
 
 template<typename Type, auto Data>
 [[nodiscard]] bool setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
-    bool accepted = false;
-
     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 data_type = type_list_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
@@ -91,7 +89,7 @@ template<typename Type, auto Data>
         if(auto * const clazz = instance->try_cast<Type>(); clazz) {
             if(value.allow_cast<data_type>()) {
                 std::invoke(Data, *clazz, value.cast<data_type>());
-                accepted = true;
+                return true;
             }
         }
     } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
@@ -101,7 +99,7 @@ template<typename Type, auto Data>
             if(auto * const clazz = instance->try_cast<Type>(); clazz) {
                 if(value.allow_cast<data_type>()) {
                     std::invoke(Data, clazz) = value.cast<data_type>();
-                    accepted = true;
+                    return true;
                 }
             }
         }
@@ -111,12 +109,12 @@ template<typename Type, auto Data>
         if constexpr(!std::is_array_v<data_type>) {
             if(value.allow_cast<data_type>()) {
                 *Data = value.cast<data_type>();
-                accepted = true;
+                return true;
             }
         }
     }
 
-    return accepted;
+    return false;
 }
 
 

+ 1 - 1
src/entt/meta/range.hpp

@@ -36,7 +36,7 @@ class meta_range {
 
         range_iterator operator++(int) ENTT_NOEXCEPT {
             range_iterator orig = *this;
-            return ++(*this), orig;
+            return it++, orig;
         }
 
         [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {

+ 1 - 0
test/CMakeLists.txt

@@ -193,6 +193,7 @@ SETUP_BASIC_TEST(meta_conv entt/meta/meta_conv.cpp)
 SETUP_BASIC_TEST(meta_ctor entt/meta/meta_ctor.cpp)
 SETUP_BASIC_TEST(meta_data entt/meta/meta_data.cpp)
 SETUP_BASIC_TEST(meta_func entt/meta/meta_func.cpp)
+SETUP_BASIC_TEST(meta_handle entt/meta/meta_handle.cpp)
 SETUP_BASIC_TEST(meta_pointer entt/meta/meta_pointer.cpp)
 SETUP_BASIC_TEST(meta_prop entt/meta/meta_prop.cpp)
 SETUP_BASIC_TEST(meta_range entt/meta/meta_range.cpp)

+ 112 - 2
test/entt/meta/meta_any.cpp

@@ -1,4 +1,3 @@
-#include <memory>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/meta/factory.hpp>
@@ -124,14 +123,35 @@ TEST_F(MetaAny, SBOAsRefConstruction) {
 
     ASSERT_TRUE(any);
     ASSERT_FALSE(any.try_cast<std::size_t>());
+    ASSERT_EQ(any.cast<int &>(), 3);
+    ASSERT_EQ(any.cast<const int &>(), 3);
     ASSERT_EQ(any.cast<int>(), 3);
     ASSERT_NE(any.data(), nullptr);
+    ASSERT_NE(std::as_const(any).data(), nullptr);
     ASSERT_EQ(any, (entt::meta_any{std::ref(value)}));
     ASSERT_NE(any, (entt::meta_any{std::ref(other)}));
     ASSERT_NE(any, entt::meta_any{42});
     ASSERT_EQ(entt::meta_any{3}, any);
 }
 
+TEST_F(MetaAny, SBOAsConstRefConstruction) {
+    int value = 3;
+    int other = 42;
+    entt::meta_any any{std::cref(value)};
+
+    ASSERT_TRUE(any);
+    ASSERT_FALSE(any.try_cast<std::size_t>());
+    ASSERT_DEATH(any.cast<int &>() = 3, ".*");
+    ASSERT_EQ(any.cast<const int &>(), 3);
+    ASSERT_EQ(any.cast<int>(), 3);
+    ASSERT_EQ(any.data(), nullptr);
+    ASSERT_NE(std::as_const(any).data(), nullptr);
+    ASSERT_EQ(any, (entt::meta_any{std::cref(value)}));
+    ASSERT_NE(any, (entt::meta_any{std::cref(other)}));
+    ASSERT_NE(any, entt::meta_any{42});
+    ASSERT_EQ(entt::meta_any{3}, any);
+}
+
 TEST_F(MetaAny, SBOCopyConstruction) {
     entt::meta_any any{42};
     entt::meta_any other{any};
@@ -215,13 +235,33 @@ TEST_F(MetaAny, NoSBOAsRefConstruction) {
 
     ASSERT_TRUE(any);
     ASSERT_FALSE(any.try_cast<std::size_t>());
+    ASSERT_EQ(any.cast<fat_t &>(), instance);
+    ASSERT_EQ(any.cast<const fat_t &>(), instance);
     ASSERT_EQ(any.cast<fat_t>(), instance);
     ASSERT_NE(any.data(), nullptr);
+    ASSERT_NE(std::as_const(any).data(), nullptr);
     ASSERT_EQ(any, (entt::meta_any{std::ref(instance)}));
     ASSERT_EQ(any, entt::meta_any{instance});
     ASSERT_NE(entt::meta_any{fat_t{}}, any);
 }
 
+TEST_F(MetaAny, NoSBOAsConstRefConstruction) {
+    int value = 3;
+    fat_t instance{&value};
+    entt::meta_any any{std::cref(instance)};
+
+    ASSERT_TRUE(any);
+    ASSERT_FALSE(any.try_cast<std::size_t>());
+    ASSERT_DEATH(any.cast<fat_t &>() = {}, ".*");
+    ASSERT_EQ(any.cast<const fat_t &>(), instance);
+    ASSERT_EQ(any.cast<fat_t>(), instance);
+    ASSERT_EQ(any.data(), nullptr);
+    ASSERT_NE(std::as_const(any).data(), nullptr);
+    ASSERT_EQ(any, (entt::meta_any{std::cref(instance)}));
+    ASSERT_EQ(any, entt::meta_any{instance});
+    ASSERT_NE(entt::meta_any{fat_t{}}, any);
+}
+
 TEST_F(MetaAny, NoSBOCopyConstruction) {
     int value = 42;
     fat_t instance{&value};
@@ -520,6 +560,72 @@ TEST_F(MetaAny, NoSBOWithVoidSwap) {
     ASSERT_EQ(lhs.cast<fat_t>().bar, &i);
 }
 
+TEST_F(MetaAny, AsRef) {
+    entt::meta_any any{42};
+    auto ref = as_ref(any);
+    auto cref = as_ref(std::as_const(any));
+
+    ASSERT_EQ(any.try_cast<int>(), any.data());
+    ASSERT_EQ(ref.try_cast<int>(), any.data());
+    ASSERT_EQ(cref.try_cast<int>(), nullptr);
+
+    ASSERT_EQ(any.try_cast<const int>(), any.data());
+    ASSERT_EQ(ref.try_cast<const int>(), any.data());
+    ASSERT_EQ(cref.try_cast<const int>(), any.data());
+
+    ASSERT_EQ(any.cast<int>(), 42);
+    ASSERT_EQ(ref.cast<int>(), 42);
+    ASSERT_EQ(cref.cast<int>(), 42);
+
+    ASSERT_EQ(any.cast<const int>(), 42);
+    ASSERT_EQ(ref.cast<const int>(), 42);
+    ASSERT_EQ(cref.cast<const int>(), 42);
+
+    ASSERT_EQ(any.cast<int &>(), 42);
+    ASSERT_EQ(any.cast<const int &>(), 42);
+    ASSERT_EQ(ref.cast<int &>(), 42);
+    ASSERT_EQ(ref.cast<const int &>(), 42);
+    ASSERT_DEATH(cref.cast<int &>() = 3, ".*");
+    ASSERT_EQ(cref.cast<const int &>(), 42);
+
+    any.cast<int &>() = 3;
+
+    ASSERT_EQ(any.cast<int>(), 3);
+    ASSERT_EQ(ref.cast<int>(), 3);
+    ASSERT_EQ(cref.cast<int>(), 3);
+
+    std::swap(ref, cref);
+
+    ASSERT_EQ(ref.try_cast<int>(), nullptr);
+    ASSERT_EQ(cref.try_cast<int>(), any.data());
+
+    ref = as_ref(ref);
+    cref = as_ref(std::as_const(cref));
+
+    ASSERT_EQ(ref.try_cast<int>(), nullptr);
+    ASSERT_EQ(cref.try_cast<int>(), nullptr);
+    ASSERT_EQ(ref.try_cast<const int>(), any.data());
+    ASSERT_EQ(cref.try_cast<const int>(), any.data());
+
+    ASSERT_DEATH(ref.cast<int &>() = 3, ".*");
+    ASSERT_DEATH(cref.cast<int &>() = 3, ".*");
+
+    ASSERT_EQ(ref.cast<const int &>(), 3);
+    ASSERT_EQ(cref.cast<const int &>(), 3);
+
+    ref = 42;
+    cref = 42;
+
+    ASSERT_NE(ref.try_cast<int>(), nullptr);
+    ASSERT_NE(cref.try_cast<int>(), nullptr);
+    ASSERT_EQ(ref.cast<int &>(), 42);
+    ASSERT_EQ(cref.cast<int &>(), 42);
+    ASSERT_EQ(ref.cast<const int &>(), 42);
+    ASSERT_EQ(cref.cast<const int &>(), 42);
+    ASSERT_NE(ref.try_cast<int>(), any.data());
+    ASSERT_NE(cref.try_cast<int>(), any.data());
+}
+
 TEST_F(MetaAny, Comparable) {
     entt::meta_any any{'c'};
 
@@ -653,6 +759,8 @@ TEST_F(MetaAny, Invoke) {
 
     ASSERT_TRUE(any.invoke("func"_hs));
     ASSERT_TRUE(any.invoke("member"_hs, 42));
+    ASSERT_FALSE(std::as_const(any).invoke("member"_hs, 42));
+    ASSERT_FALSE(as_ref(std::as_const(any)).invoke("member"_hs, 42));
     ASSERT_FALSE(any.invoke("non_existent"_hs, 42));
 
     ASSERT_EQ(clazz_t::c, 'd');
@@ -667,9 +775,11 @@ TEST_F(MetaAny, SetGet) {
 
     ASSERT_TRUE(any.set("value"_hs, 42));
 
-    const auto value = any.get("value"_hs);
+    const auto value = std::as_const(any).get("value"_hs);
 
     ASSERT_TRUE(value);
+    ASSERT_EQ(value, any.get("value"_hs));
+    ASSERT_EQ(value, as_ref(std::as_const(any)).get("value"_hs));
     ASSERT_NE(value.try_cast<int>(), nullptr);
     ASSERT_EQ(value.cast<int>(), 42);
     ASSERT_EQ(instance.value, 42);

+ 27 - 3
test/entt/meta/meta_ctor.cpp

@@ -136,8 +136,19 @@ TEST_F(MetaCtor, CastAndConvert) {
     ASSERT_EQ(any.cast<clazz_t>().c, 'c');
 }
 
+TEST_F(MetaCtor, ConstNonConstRefArgs) {
+    int ivalue = 42;
+    char cvalue = 'c';
+
+    auto any = entt::resolve<clazz_t>().ctor<int, char>().invoke(std::ref(ivalue), std::cref(cvalue));
+
+    ASSERT_TRUE(any);
+    ASSERT_EQ(any.cast<clazz_t>().i, 42);
+    ASSERT_EQ(any.cast<clazz_t>().c, 'c');
+}
+
 TEST_F(MetaCtor, FuncMetaAnyArgs) {
-    auto any = entt::resolve<clazz_t>().ctor<base_t, int>().invoke(entt::meta_any{base_t{'c'}}, entt::meta_any{42});
+    auto any = entt::resolve<clazz_t>().ctor<int>().invoke(entt::meta_any{42});
 
     ASSERT_TRUE(any);
     ASSERT_EQ(any.cast<clazz_t>().i, 42);
@@ -145,8 +156,8 @@ TEST_F(MetaCtor, FuncMetaAnyArgs) {
 }
 
 TEST_F(MetaCtor, FuncInvalidArgs) {
-    auto ctor = entt::resolve<clazz_t>().ctor<const base_t &, int>();
-    ASSERT_FALSE(ctor.invoke(base_t{}, 'c'));
+    auto ctor = entt::resolve<clazz_t>().ctor<int>();
+    ASSERT_FALSE(ctor.invoke('c'));
 }
 
 TEST_F(MetaCtor, FuncCastAndConvert) {
@@ -157,6 +168,19 @@ TEST_F(MetaCtor, FuncCastAndConvert) {
     ASSERT_EQ(any.cast<clazz_t>().c, 'c');
 }
 
+TEST_F(MetaCtor, FuncConstNonConstRefArgs) {
+    int ivalue = 42;
+    auto ctor = entt::resolve<clazz_t>().ctor<int>();
+
+    auto any = ctor.invoke(std::ref(ivalue));
+    auto other = ctor.invoke(std::cref(ivalue));
+
+    ASSERT_TRUE(any);
+    ASSERT_TRUE(other);
+    ASSERT_EQ(any.cast<clazz_t>().i, 42);
+    ASSERT_EQ(other.cast<clazz_t>().i, 42);
+}
+
 TEST_F(MetaCtor, ExternalMemberFunction) {
     using namespace entt::literals;
 

+ 74 - 8
test/entt/meta/meta_data.cpp

@@ -72,6 +72,7 @@ struct MetaData: ::testing::Test {
 
         entt::meta<clazz_t>().type("clazz"_hs)
             .data<&clazz_t::i, entt::as_ref_t>("i"_hs).prop(3, 0)
+            .data<&clazz_t::i, entt::as_cref_t>("ci"_hs)
             .data<&clazz_t::j>("j"_hs).prop(true, 1)
             .data<&clazz_t::h>("h"_hs).prop(property_t::random, 2)
             .data<&clazz_t::k>("k"_hs).prop(property_t::value, 3)
@@ -276,6 +277,40 @@ TEST_F(MetaData, SetConvert) {
     ASSERT_EQ(instance.i, 3);
 }
 
+TEST_F(MetaData, SetByRef) {
+    using namespace entt::literals;
+
+    entt::meta_any any{clazz_t{}};
+    int value{42};
+
+    ASSERT_EQ(any.cast<clazz_t>().i, 0);
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, std::ref(value)));
+    ASSERT_EQ(any.cast<clazz_t>().i, 42);
+
+    value = 3;
+    entt::meta_any wrapper{std::ref(value)};
+
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, as_ref(wrapper)));
+    ASSERT_EQ(any.cast<clazz_t>().i, 3);
+}
+
+TEST_F(MetaData, SetByConstRef) {
+    using namespace entt::literals;
+
+    entt::meta_any any{clazz_t{}};
+    int value{42};
+
+    ASSERT_EQ(any.cast<clazz_t>().i, 0);
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, std::cref(value)));
+    ASSERT_EQ(any.cast<clazz_t>().i, 42);
+
+    value = 3;
+    entt::meta_any wrapper{std::cref(value)};
+
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, as_ref(wrapper)));
+    ASSERT_EQ(any.cast<clazz_t>().i, 3);
+}
+
 TEST_F(MetaData, SetterGetterAsFreeFunctions) {
     using namespace entt::literals;
 
@@ -378,6 +413,27 @@ TEST_F(MetaData, SetterGetterReadOnlyDataMember) {
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
 }
 
+TEST_F(MetaData, ConstInstance) {
+    using namespace entt::literals;
+
+    clazz_t instance{};
+
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).get(instance));
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(instance, 3));
+    ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)));
+    ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).set(std::as_const(instance), 3));
+
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).get(instance));
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).set(instance, 3));
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).get(std::as_const(instance)));
+    ASSERT_FALSE(entt::resolve<clazz_t>().data("ci"_hs).set(std::as_const(instance), 3));
+
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).get(instance));
+    ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).set(instance, 3));
+    ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).get(std::as_const(instance)));
+    ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).set(std::as_const(instance), 3));
+}
+
 TEST_F(MetaData, ArrayStatic) {
     using namespace entt::literals;
 
@@ -426,20 +482,30 @@ TEST_F(MetaData, AsRef) {
     using namespace entt::literals;
 
     clazz_t instance{};
+    auto data = entt::resolve<clazz_t>().data("i"_hs);
 
-    auto h_data = entt::resolve<clazz_t>().data("h"_hs);
-    auto i_data = entt::resolve<clazz_t>().data("i"_hs);
-
-    ASSERT_EQ(h_data.type(), entt::resolve<int>());
-    ASSERT_EQ(i_data.type(), entt::resolve<int>());
+    ASSERT_EQ(instance.i, 0);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
 
-    h_data.get(instance).cast<int &>() = 3;
-    i_data.get(instance).cast<int &>() = 3;
+    data.get(instance).cast<int &>() = 3;
 
-    ASSERT_NE(instance.h, 3);
     ASSERT_EQ(instance.i, 3);
 }
 
+TEST_F(MetaData, AsConstRef) {
+    using namespace entt::literals;
+
+    clazz_t instance{};
+    auto data = entt::resolve<clazz_t>().data("ci"_hs);
+
+    ASSERT_EQ(instance.i, 0);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
+    ASSERT_DEATH(data.get(instance).cast<int &>() = 3, ".*");
+    ASSERT_EQ(data.get(instance).cast<const int &>(), 0);
+    ASSERT_EQ(data.get(instance).cast<int>(), 0);
+    ASSERT_EQ(instance.i, 0);
+}
+
 TEST_F(MetaData, FromBase) {
     using namespace entt::literals;
 

+ 49 - 10
test/entt/meta/meta_func.cpp

@@ -76,7 +76,8 @@ struct MetaFunc: ::testing::Test {
             .func<&func_t::h>("h"_hs).prop(true, false)
             .func<&func_t::k>("k"_hs).prop(true, false)
             .func<&func_t::v, entt::as_void_t>("v"_hs)
-            .func<&func_t::a, entt::as_ref_t>("a"_hs);
+            .func<&func_t::a, entt::as_ref_t>("a"_hs)
+            .func<&func_t::a, entt::as_cref_t>("ca"_hs);
     }
 
     void SetUp() override {
@@ -306,6 +307,46 @@ TEST_F(MetaFunc, CastAndConvert) {
     ASSERT_EQ(any.cast<int>(), 9);
 }
 
+TEST_F(MetaFunc, ArgsByRef) {
+    using namespace entt::literals;
+
+    auto func = entt::resolve<func_t>().func("h"_hs);
+    func_t::value = 2;
+    entt::meta_any any{3};
+    int value = 4;
+
+    ASSERT_EQ(func.invoke({}, std::ref(value)).cast<int>(), 8);
+    ASSERT_EQ(func.invoke({}, as_ref(any)).cast<int>(), 6);
+    ASSERT_EQ(any.cast<int>(), 6);
+    ASSERT_EQ(value, 8);
+}
+
+TEST_F(MetaFunc, ArgsByConstRef) {
+    using namespace entt::literals;
+
+    func_t instance{};
+    auto func = entt::resolve<func_t>().func("g"_hs);
+    entt::meta_any any{2};
+    int value = 3;
+
+    ASSERT_TRUE(func.invoke(instance, std::cref(value)));
+    ASSERT_EQ(func_t::value, 9);
+
+    ASSERT_TRUE(func.invoke(instance, as_ref(std::as_const(any))));
+    ASSERT_EQ(func_t::value, 4);
+}
+
+TEST_F(MetaFunc, ConstInstance) {
+    using namespace entt::literals;
+
+    func_t instance{};
+    auto any = entt::resolve<func_t>().func("f1"_hs).invoke(std::as_const(instance), 2);
+
+    ASSERT_FALSE(entt::resolve<func_t>().func("g"_hs).invoke(std::as_const(instance), 42));
+    ASSERT_TRUE(any);
+    ASSERT_EQ(any.cast<int>(), 4);
+}
+
 TEST_F(MetaFunc, AsVoid) {
     using namespace entt::literals;
 
@@ -328,18 +369,16 @@ TEST_F(MetaFunc, AsRef) {
     ASSERT_EQ(instance.value, 3);
 }
 
-TEST_F(MetaFunc, ByReference) {
+TEST_F(MetaFunc, AsConstRef) {
     using namespace entt::literals;
 
-    auto func = entt::resolve<func_t>().func("h"_hs);
-    func_t::value = 2;
-    entt::meta_any any{3};
-    int value = 4;
+    func_t instance{};
+    auto func = entt::resolve<func_t>().func("ca"_hs);
 
-    ASSERT_EQ(func.invoke({}, std::ref(value)).cast<int>(), 8);
-    ASSERT_EQ(func.invoke({}, as_ref(any)).cast<int>(), 6);
-    ASSERT_EQ(any.cast<int>(), 6);
-    ASSERT_EQ(value, 8);
+    ASSERT_DEATH((func.invoke(instance).cast<int &>() = 3), ".*");
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+    ASSERT_EQ(func.invoke(instance).cast<const int &>(), 3);
+    ASSERT_EQ(func.invoke(instance).cast<int>(), 3);
 }
 
 TEST_F(MetaFunc, FromBase) {

+ 43 - 0
test/entt/meta/meta_handle.cpp

@@ -0,0 +1,43 @@
+#include <gtest/gtest.h>
+#include <entt/core/hashed_string.hpp>
+#include <entt/meta/factory.hpp>
+#include <entt/meta/meta.hpp>
+#include <entt/meta/resolve.hpp>
+
+struct clazz_t {
+	void incr() { ++value; }
+	void decr() { --value; }
+	int value;
+};
+
+struct MetaHandle: ::testing::Test {
+	static void SetUpTestCase() {
+		using namespace entt::literals;
+
+		entt::meta<clazz_t>()
+			.func<&clazz_t::incr>("incr"_hs)
+			.func<&clazz_t::decr>("decr"_hs);
+	}
+};
+
+TEST_F(MetaHandle, Functionalities) {
+	using namespace entt::literals;
+
+	clazz_t instance{};
+	entt::meta_handle handle{};
+
+	ASSERT_FALSE(*handle);
+
+	handle = entt::meta_handle{instance};
+
+	ASSERT_TRUE(*handle);
+	ASSERT_TRUE((*handle).invoke("incr"_hs));
+	ASSERT_EQ(instance.value, 1);
+
+	entt::meta_any any{std::ref(instance)};
+	handle = entt::meta_handle{any};
+
+	ASSERT_FALSE(std::as_const(handle)->invoke("decr"_hs));
+	ASSERT_TRUE(handle->invoke("decr"_hs));
+	ASSERT_EQ(instance.value, 0);
+}

+ 9 - 3
test/entt/meta/meta_pointer.cpp

@@ -41,7 +41,8 @@ TEST(MetaPointerLike, DereferenceOperatorConstType) {
     ASSERT_EQ(deref.type(), entt::resolve<int>());
 
     ASSERT_EQ(deref.try_cast<int>(), nullptr);
-    ASSERT_NE(deref.try_cast<const int>(), nullptr);
+    ASSERT_EQ(deref.try_cast<const int>(), &value);
+    ASSERT_DEATH(deref.cast<int &>(), ".*");
     ASSERT_EQ(deref.cast<const int &>(), 42);
 }
 
@@ -87,10 +88,15 @@ TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
     ASSERT_EQ(*value, 42);
 }
 
-TEST(MetaPointerLike, PointerToMoveOnlyType) {
+TEST(MetaPointerLike, PointerToConstMoveOnlyType) {
     const not_copyable_t instance;
     entt::meta_any any{&instance};
+    auto deref = *any;
 
     ASSERT_TRUE(any);
-    ASSERT_TRUE(*any);
+    ASSERT_TRUE(deref);
+
+    ASSERT_DEATH(deref.cast<not_copyable_t &>(), ".*");
+    ASSERT_EQ(deref.try_cast<not_copyable_t>(), nullptr);
+    ASSERT_NE(deref.try_cast<const not_copyable_t>(), nullptr);
 }