Browse Source

any: rvalue any_cast no longer forces by-copy constructor (close #730)

Michele Caini 4 years ago
parent
commit
94d5b11191
3 changed files with 24 additions and 7 deletions
  1. 11 4
      src/entt/core/any.hpp
  2. 12 2
      test/entt/core/any.cpp
  3. 1 1
      test/entt/meta/meta_prop.cpp

+ 11 - 4
src/entt/core/any.hpp

@@ -372,10 +372,17 @@ Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
 /*! @copydoc any_cast */
 template<typename Type, std::size_t Len, std::size_t Align>
 Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
-    // forces const on non-reference types to make them work also with wrappers for const references
-    auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
-    ENTT_ASSERT(instance, "Invalid instance");
-    return static_cast<Type>(std::move(*instance));
+    if constexpr(std::is_copy_constructible_v<std::decay_t<Type>>) {
+        if(auto * const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
+            return static_cast<Type>(std::move(*instance));
+        } else {
+            return any_cast<Type>(data);
+        }
+    } else {
+        auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
+        ENTT_ASSERT(instance, "Invalid instance");
+        return static_cast<Type>(std::move(*instance));
+    }
 }
 
 

+ 12 - 2
test/entt/core/any.cpp

@@ -1,5 +1,6 @@
 #include <algorithm>
-#include <string.h>
+#include <string>
+#include <type_traits>
 #include <unordered_map>
 #include <vector>
 #include <gtest/gtest.h>
@@ -960,8 +961,17 @@ TEST_F(Any, AnyCast) {
     ASSERT_DEATH(entt::any_cast<double &>(any), "");
     ASSERT_EQ(entt::any_cast<const int &>(cany), 42);
     ASSERT_DEATH(entt::any_cast<const double &>(cany), "");
-    ASSERT_EQ(entt::any_cast<int>(entt::any{42}), 42);
+
+    not_copyable<1> instance{};
+    instance.payload[0u] = 42.;
+    entt::any ref{entt::forward_as_any(instance)};
+    entt::any cref{entt::forward_as_any(std::as_const(instance).payload[0u])};
+
+    ASSERT_EQ(entt::any_cast<not_copyable<1>>(std::move(ref)).payload[0u], 42.);
+    ASSERT_DEATH(entt::any_cast<not_copyable<1>>(std::as_const(ref).as_ref()), "");
+    ASSERT_EQ(entt::any_cast<double>(std::move(cref)), 42.);
     ASSERT_DEATH(entt::any_cast<double>(entt::any{42}), "");
+    ASSERT_EQ(entt::any_cast<int>(entt::any{42}), 42);
 }
 
 TEST_F(Any, MakeAny) {

+ 1 - 1
test/entt/meta/meta_prop.cpp

@@ -1,4 +1,4 @@
-#include <string.h>
+#include <string>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/meta/factory.hpp>