소스 검색

meta: revert automatic policy (too convenient a feature)

skypjack 5 달 전
부모
커밋
6ecf1f35c0

+ 1 - 0
CMakeLists.txt

@@ -169,6 +169,7 @@ if(ENTT_INCLUDE_HEADERS)
         meta/meta.hpp
         meta/node.hpp
         meta/pointer.hpp
+        meta/policy.hpp
         meta/range.hpp
         meta/resolve.hpp
         meta/template.hpp

+ 1 - 0
src/entt/entt.hpp

@@ -50,6 +50,7 @@ namespace entt {}
 #include "meta/meta.hpp"
 #include "meta/node.hpp"
 #include "meta/pointer.hpp"
+#include "meta/policy.hpp"
 #include "meta/range.hpp"
 #include "meta/resolve.hpp"
 #include "meta/template.hpp"

+ 35 - 17
src/entt/meta/factory.hpp

@@ -19,6 +19,7 @@
 #include "fwd.hpp"
 #include "meta.hpp"
 #include "node.hpp"
+#include "policy.hpp"
 #include "range.hpp"
 #include "resolve.hpp"
 #include "utility.hpp"
@@ -251,13 +252,15 @@ public:
      * type is a built-in one or not.
      *
      * @tparam Candidate The actual function to use as a constructor.
+     * @tparam Policy Optional policy (no policy set by default).
      * @return A meta factory for the parent type.
      */
-    template<auto Candidate>
+    template<auto Candidate, typename Policy = as_is_t>
     meta_factory ctor() noexcept {
         using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
+        static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
         static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
-        base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate>});
+        base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
         return *this;
     }
 
@@ -285,12 +288,13 @@ public:
     /**
      * @brief Assigns a meta data to a meta type.
      * @tparam Data The actual variable to attach to the meta type.
+     * @tparam Policy Optional policy (no policy set by default).
      * @param name A custom unique identifier as a **string literal**.
      * @return A meta factory for the given type.
      */
-    template<auto Data>
+    template<auto Data, typename Policy = as_is_t>
     meta_factory data(const char *name) noexcept {
-        return data<Data>(entt::hashed_string::value(name), name);
+        return data<Data, Policy>(entt::hashed_string::value(name), name);
     }
 
     /**
@@ -302,14 +306,16 @@ public:
      * reflected object will appear as if they were part of the type itself.
      *
      * @tparam Data The actual variable to attach to the meta type.
+     * @tparam Policy Optional policy (no policy set by default).
      * @param id Unique identifier.
      * @param name An optional name for the meta data as a **string literal**.
      * @return A meta factory for the parent type.
      */
-    template<auto Data>
+    template<auto Data, typename Policy = as_is_t>
     meta_factory data(const id_type id, const char *name = nullptr) noexcept {
         if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
             using data_type = std::invoke_result_t<decltype(Data), Type &>;
+            static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
 
             base_type::data(
                 internal::meta_data_node{
@@ -321,10 +327,16 @@ public:
                     &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
                     &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
                     &meta_setter<Type, Data>,
-                    &meta_getter<Type, Data>});
+                    &meta_getter<Type, Data, Policy>});
         } else {
             using data_type = std::remove_pointer_t<decltype(Data)>;
 
+            if constexpr(std::is_pointer_v<decltype(Data)>) {
+                static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
+            } else {
+                static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
+            }
+
             base_type::data(
                 internal::meta_data_node{
                     id,
@@ -334,7 +346,7 @@ public:
                     &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
                     &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
                     &meta_setter<Type, Data>,
-                    &meta_getter<Type, Data>});
+                    &meta_getter<Type, Data, Policy>});
         }
 
         return *this;
@@ -345,12 +357,13 @@ public:
      * getter.
      * @tparam Setter The actual function to use as a setter.
      * @tparam Getter The actual function to use as a getter.
+     * @tparam Policy Optional policy (no policy set by default).
      * @param name A custom unique identifier as a **string literal**.
      * @return A meta factory for the given type.
      */
-    template<auto Setter, auto Getter>
+    template<auto Setter, auto Getter, typename Policy = as_is_t>
     meta_factory data(const char *name) noexcept {
-        return data<Setter, Getter>(entt::hashed_string::value(name), name);
+        return data<Setter, Getter, Policy>(entt::hashed_string::value(name), name);
     }
 
     /**
@@ -369,13 +382,15 @@ public:
      *
      * @tparam Setter The actual function to use as a setter.
      * @tparam Getter The actual function to use as a getter.
+     * @tparam Policy Optional policy (no policy set by default).
      * @param id Unique identifier.
      * @param name An optional name for the meta data as a **string literal**.
      * @return A meta factory for the parent type.
      */
-    template<auto Setter, auto Getter>
+    template<auto Setter, auto Getter, typename Policy = as_is_t>
     meta_factory data(const id_type id, const char *name = nullptr) noexcept {
         using descriptor = meta_function_helper_t<Type, decltype(Getter)>;
+        static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
 
         if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
             base_type::data(
@@ -388,7 +403,7 @@ public:
                     &internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
                     &meta_arg<type_list<>>,
                     &meta_setter<Type, Setter>,
-                    &meta_getter<Type, Getter>});
+                    &meta_getter<Type, Getter, Policy>});
         } else {
             using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
 
@@ -402,7 +417,7 @@ public:
                     &internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
                     &meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(args_type::size != 1u), args_type>>>,
                     &meta_setter<Type, Setter>,
-                    &meta_getter<Type, Getter>});
+                    &meta_getter<Type, Getter, Policy>});
         }
 
         return *this;
@@ -411,12 +426,13 @@ public:
     /**
      * @brief Assigns a meta function to a meta type.
      * @tparam Candidate The actual function to attach to the meta function.
+     * @tparam Policy Optional policy (no policy set by default).
      * @param name A custom unique identifier as a **string literal**.
      * @return A meta factory for the given type.
      */
-    template<auto Candidate>
+    template<auto Candidate, typename Policy = as_is_t>
     meta_factory func(const char *name) noexcept {
-        return func<Candidate>(entt::hashed_string::value(name), name);
+        return func<Candidate, Policy>(entt::hashed_string::value(name), name);
     }
 
     /**
@@ -428,13 +444,15 @@ public:
      * reflected object will appear as if they were part of the type itself.
      *
      * @tparam Candidate The actual function to attach to the meta type.
+     * @tparam Policy Optional policy (no policy set by default).
      * @param id Unique identifier.
      * @param name An optional name for the function as a **string literal**.
      * @return A meta factory for the parent type.
      */
-    template<auto Candidate>
+    template<auto Candidate, typename Policy = as_is_t>
     meta_factory func(const id_type id, const char *name = nullptr) noexcept {
         using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
+        static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
 
         base_type::func(
             internal::meta_func_node{
@@ -442,9 +460,9 @@ public:
                 name,
                 (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
                 descriptor::args_type::size,
-                &internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
+                &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
                 &meta_arg<typename descriptor::args_type>,
-                &meta_invoke<Type, Candidate>});
+                &meta_invoke<Type, Candidate, Policy>});
 
         return *this;
     }

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

@@ -0,0 +1,58 @@
+#ifndef ENTT_META_POLICY_HPP
+#define ENTT_META_POLICY_HPP
+
+#include <type_traits>
+
+namespace entt {
+
+/*! @brief Empty class type used to request the _as ref_ policy. */
+struct as_ref_t final {
+    /*! @cond TURN_OFF_DOXYGEN */
+    template<typename Type>
+    static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
+    /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as cref_ policy. */
+struct as_cref_t final {
+    /*! @cond TURN_OFF_DOXYGEN */
+    template<typename Type>
+    static constexpr bool value = std::is_reference_v<Type>;
+    /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as-is_ policy. */
+struct as_is_t final {
+    /*! @cond TURN_OFF_DOXYGEN */
+    template<typename>
+    static constexpr bool value = true;
+    /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as void_ policy. */
+struct as_void_t final {
+    /*! @cond TURN_OFF_DOXYGEN */
+    template<typename>
+    static constexpr bool value = true;
+    /*! @endcond */
+};
+
+/**
+ * @brief Provides the member constant `value` to true if a type also is a meta
+ * policy, false otherwise.
+ * @tparam Type Type to check.
+ */
+template<typename Type>
+struct is_meta_policy
+    : std::bool_constant<std::is_same_v<Type, as_ref_t> || std::is_same_v<Type, as_cref_t> || std::is_same_v<Type, as_is_t> || std::is_same_v<Type, as_void_t>> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Type to check.
+ */
+template<typename Type>
+inline constexpr bool is_meta_policy_v = is_meta_policy<Type>::value;
+
+} // namespace entt
+
+#endif

+ 55 - 40
src/entt/meta/utility.hpp

@@ -9,6 +9,7 @@
 #include "../locator/locator.hpp"
 #include "meta.hpp"
 #include "node.hpp"
+#include "policy.hpp"
 
 namespace entt {
 
@@ -76,7 +77,7 @@ template<typename Type, typename Ret, typename Class>
 struct meta_function_descriptor<Type, Ret Class::*>
     : meta_function_descriptor_traits<
           Ret &,
-          std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Ret>, type_list<Class &, Ret>>,
+          std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
           !std::is_base_of_v<Class, Type>,
           false> {};
 
@@ -151,66 +152,73 @@ template<typename Type, typename Candidate>
 using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
 
 /**
- * @brief Wraps a value and returns it.
+ * @brief Wraps a value depending on the given policy.
  *
  * This function always returns a wrapped value in the requested context.<br/>
  * Therefore, if the passed value is itself a wrapped object with a different
  * context, it undergoes a rebinding to the requested context.
  *
+ * @tparam Policy Optional policy (no policy set by default).
  * @tparam Type Type of value to wrap.
  * @param ctx The context from which to search for meta types.
  * @param value Value to wrap.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type>
-[[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
-    if constexpr(std::is_lvalue_reference_v<Type> && !std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, meta_any>) {
-        return meta_any{ctx, std::in_place_type<Type>, std::forward<Type>(value)};
+template<typename Policy = as_is_t, typename Type>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
+    if constexpr(std::is_same_v<Policy, as_void_t>) {
+        return meta_any{ctx, std::in_place_type<void>};
+    } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
+        return meta_any{ctx, std::in_place_type<Type>, value};
+    } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+        static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
+        return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
     } else {
         return meta_any{ctx, std::forward<Type>(value)};
     }
 }
 
 /**
- * @brief Wraps a value and returns it.
+ * @brief Wraps a value depending on the given policy.
+ * @tparam Policy Optional policy (no policy set by default).
  * @tparam Type Type of value to wrap.
  * @param value Value to wrap.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type>
-[[nodiscard]] meta_any meta_dispatch(Type &&value) {
-    return meta_dispatch<Type>(locator<meta_ctx>::value_or(), std::forward<Type>(value));
+template<typename Policy = as_is_t, typename Type>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(Type &&value) {
+    return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), std::forward<Type>(value));
 }
 
 /*! @cond TURN_OFF_DOXYGEN */
 namespace internal {
 
-template<typename Candidate, typename... Args>
+template<typename Policy, typename Candidate, typename... Args>
 [[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
     if constexpr(std::is_void_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...))>) {
         std::invoke(std::forward<Candidate>(candidate), args...);
         return meta_any{ctx, std::in_place_type<void>};
     } else {
-        return meta_dispatch(ctx, std::invoke(std::forward<Candidate>(candidate), args...));
+        return meta_dispatch<Policy>(ctx, std::invoke(std::forward<Candidate>(candidate), args...));
     }
 }
 
-template<typename Type, typename Candidate, std::size_t... Index>
+template<typename Type, typename Policy, typename Candidate, std::size_t... Index>
 [[nodiscard]] meta_any meta_invoke(meta_handle &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, std::index_sequence<Index...>) {
     using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
 
     // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
     if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
         if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
-            return meta_invoke_with_args(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+            return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
         }
     } else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
         if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
-            return meta_invoke_with_args(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+            return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
         }
     } else {
         if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
-            return meta_invoke_with_args(instance->context(), std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+            return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
         }
     }
     // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
@@ -301,22 +309,23 @@ template<typename Type, auto Data>
  * @brief Gets the value of a given variable.
  * @tparam Type Reflected type to which the variable is associated.
  * @tparam Data The actual variable to get.
+ * @tparam Policy Optional policy (no policy set by default).
  * @param instance An opaque instance of the underlying type, if required.
  * @return A meta any containing the value of the underlying variable.
  */
-template<typename Type, auto Data>
-[[nodiscard]] meta_any meta_getter(meta_handle instance) {
+template<typename Type, auto Data, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(meta_handle instance) {
     if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
         if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
             if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
                 if(auto *clazz = instance->try_cast<Type>(); clazz) {
-                    return internal::meta_invoke_with_args(instance->context(), Data, *clazz);
+                    return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *clazz));
                 }
             }
 
             if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
                 if(auto *fallback = instance->try_cast<const Type>(); fallback) {
-                    return internal::meta_invoke_with_args(instance->context(), Data, *fallback);
+                    return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *fallback));
                 }
             }
         }
@@ -326,38 +335,40 @@ template<typename Type, auto Data>
         if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
             return meta_any{meta_ctx_arg, instance->context()};
         } else {
-            return meta_dispatch(instance->context(), *Data);
+            return meta_dispatch<Policy>(instance->context(), *Data);
         }
     } else {
-        return meta_dispatch(instance->context(), Data);
+        return meta_dispatch<Policy>(instance->context(), Data);
     }
 }
 
 /**
  * @brief Tries to _invoke_ an object given a list of erased parameters.
  * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
  * @tparam Candidate The type of the actual object to _invoke_.
  * @param instance An opaque instance of the underlying type, if required.
  * @param candidate The actual object to _invoke_.
  * @param args Parameters to use to _invoke_ the object.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type, typename Candidate>
-[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
-    return internal::meta_invoke<Type>(instance, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
+template<typename Type, typename Policy = as_is_t, typename Candidate>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
+    return internal::meta_invoke<Type, Policy>(instance, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
 }
 
 /**
  * @brief Tries to invoke a function given a list of erased parameters.
  * @tparam Type Reflected type to which the function is associated.
  * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
  * @param instance An opaque instance of the underlying type, if required.
  * @param args Parameters to use to invoke the function.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type, auto Candidate>
-[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
-    return internal::meta_invoke<Type>(instance, Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, meta_any *const args) {
+    return internal::meta_invoke<Type, Policy>(instance, Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
 }
 
 /**
@@ -398,35 +409,37 @@ template<typename Type, typename... Args>
  * It's up to the caller to bind the arguments to the right context(s).
  *
  * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
  * @tparam Candidate The type of the actual object to _invoke_.
  * @param ctx The context from which to search for meta types.
  * @param candidate The actual object to _invoke_.
  * @param args Parameters to use to _invoke_ the object.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type, typename Candidate>
+template<typename Type, typename Policy = as_is_t, typename Candidate>
 [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
     if constexpr(meta_function_helper_t<Type, Candidate>::is_static || std::is_class_v<std::remove_cv_t<std::remove_reference_t<Candidate>>>) {
         meta_handle placeholder{meta_ctx_arg, ctx};
-        return internal::meta_invoke<Type>(placeholder, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
+        return internal::meta_invoke<Type, Policy>(placeholder, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
     } else {
         meta_handle target{*args};
         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
-        return internal::meta_invoke<Type>(target, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
+        return internal::meta_invoke<Type, Policy>(target, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
     }
 }
 
 /**
  * @brief Tries to construct an instance given a list of erased parameters.
  * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
  * @tparam Candidate The type of the actual object to _invoke_.
  * @param candidate The actual object to _invoke_.
  * @param args Parameters to use to _invoke_ the object.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type, typename Candidate>
-[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
-    return meta_construct<Type>(locator<meta_ctx>::value_or(), std::forward<Candidate>(candidate), args);
+template<typename Type, typename Policy = as_is_t, typename Candidate>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(Candidate &&candidate, meta_any *const args) {
+    return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), std::forward<Candidate>(candidate), args);
 }
 
 /**
@@ -438,25 +451,27 @@ template<typename Type, typename Candidate>
  *
  * @tparam Type Reflected type to which the function is associated.
  * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
  * @param ctx The context from which to search for meta types.
  * @param args Parameters to use to invoke the function.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type, auto Candidate>
-[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
-    return meta_construct<Type>(ctx, Candidate, args);
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(const meta_ctx &ctx, meta_any *const args) {
+    return meta_construct<Type, Policy>(ctx, Candidate, args);
 }
 
 /**
  * @brief Tries to construct an instance given a list of erased parameters.
  * @tparam Type Reflected type to which the function is associated.
  * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
  * @param args Parameters to use to invoke the function.
  * @return A meta any containing the returned value, if any.
  */
-template<typename Type, auto Candidate>
-[[nodiscard]] meta_any meta_construct(meta_any *const args) {
-    return meta_construct<Type, Candidate>(locator<meta_ctx>::value_or(), args);
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(meta_any *const args) {
+    return meta_construct<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), args);
 }
 
 } // namespace entt

+ 2 - 1
test/entt/meta/meta_ctor.cpp

@@ -7,6 +7,7 @@
 #include <entt/meta/context.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
+#include <entt/meta/policy.hpp>
 #include <entt/meta/resolve.hpp>
 
 struct base {
@@ -59,7 +60,7 @@ struct MetaCtor: ::testing::Test {
 
         entt::meta_factory<clazz>{}
             .type("clazz"_hs)
-            .ctor<&entt::registry::emplace_or_replace<clazz, const int &, const char &>>()
+            .ctor<&entt::registry::emplace_or_replace<clazz, const int &, const char &>, entt::as_ref_t>()
             .ctor<const base &, int &>()
             .ctor<const int &, char>()
             .ctor<entt::overload<clazz(int)>(clazz::factory)>()

+ 5 - 15
test/entt/meta/meta_data.cpp

@@ -9,6 +9,7 @@
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
 #include <entt/meta/node.hpp>
+#include <entt/meta/policy.hpp>
 #include <entt/meta/range.hpp>
 #include <entt/meta/resolve.hpp>
 #include "../../common/config.h"
@@ -66,17 +67,6 @@ struct array {
     int local[4];                // NOLINT
 };
 
-// waiting for C++20 and lambdas inlined as template arguments
-namespace {
-
-const int &clazz_i_as_const_reference(const clazz &elem) {
-    return elem.i;
-}
-
-void clazz_i_as_void(const clazz &) {}
-
-} // namespace
-
 struct MetaData: ::testing::Test {
     void SetUp() override {
         using namespace entt::literals;
@@ -92,10 +82,10 @@ struct MetaData: ::testing::Test {
 
         entt::meta_factory<clazz>{}
             .type("clazz"_hs)
-            .data<&clazz::i>("i"_hs)
+            .data<&clazz::i, entt::as_ref_t>("i"_hs)
             .custom<char>('c')
             .traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three)
-            .data<&clazz::i, &clazz_i_as_const_reference>("ci"_hs)
+            .data<&clazz::i, entt::as_cref_t>("ci"_hs)
             .data<&clazz::j>("j")
             .traits(test::meta_traits::one)
             .data<&clazz::h>("h"_hs, "hhh")
@@ -104,7 +94,7 @@ struct MetaData: ::testing::Test {
             .traits(test::meta_traits::three)
             .data<'c'>("l"_hs)
             .data<&clazz::instance>("base"_hs)
-            .data<&clazz::i, clazz_i_as_void>("void"_hs)
+            .data<&clazz::i, entt::as_void_t>("void"_hs)
             .conv<int>();
 
         entt::meta_factory<setter_getter>{}
@@ -544,7 +534,7 @@ TEST_F(MetaData, AsVoid) {
 
     ASSERT_TRUE(data);
     ASSERT_EQ(data.arity(), 1u);
-    ASSERT_EQ(data.type(), entt::resolve<void>());
+    ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.arg(0u), entt::resolve<int>());
     ASSERT_TRUE(data.set(instance, 1));
     ASSERT_EQ(instance.i, 1);

+ 5 - 17
test/entt/meta/meta_func.cpp

@@ -7,6 +7,7 @@
 #include <entt/entity/registry.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
+#include <entt/meta/policy.hpp>
 #include <entt/meta/range.hpp>
 #include <entt/meta/resolve.hpp>
 #include "../../common/config.h"
@@ -88,19 +89,6 @@ double double_member(const double &value) {
     return value * value;
 }
 
-// waiting for C++20 and lambdas inlined as template arguments
-namespace {
-
-void elem_v_as_void(const function &elem, int &iv) {
-    static_cast<void>(elem.v(iv));
-}
-
-const int &elem_a_as_const(function &elem) {
-    return elem.a();
-}
-
-} // namespace
-
 struct MetaFunc: ::testing::Test {
     void SetUp() override {
         using namespace entt::literals;
@@ -124,7 +112,7 @@ struct MetaFunc: ::testing::Test {
 
         entt::meta_factory<function>{}
             .type("func"_hs)
-            .func<&entt::registry::emplace_or_replace<function>>("emplace"_hs)
+            .func<&entt::registry::emplace_or_replace<function>, entt::as_ref_t>("emplace"_hs)
             .traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three)
             .func<entt::overload<int(const base &, int, int)>(&function::f)>("f3"_hs)
             .traits(test::meta_traits::three)
@@ -137,9 +125,9 @@ struct MetaFunc: ::testing::Test {
             .custom<char>('c')
             .func<function::h>("h"_hs)
             .func<function::k>("k"_hs)
-            .func<&elem_v_as_void>("v"_hs)
-            .func<&function::a>("a"_hs)
-            .func<&elem_a_as_const>("ca"_hs)
+            .func<&function::v, entt::as_void_t>("v"_hs)
+            .func<&function::a, entt::as_ref_t>("a"_hs)
+            .func<&function::a, entt::as_cref_t>("ca"_hs)
             .conv<int>();
     }
 

+ 9 - 6
test/entt/meta/meta_utility.cpp

@@ -4,6 +4,7 @@
 #include <gtest/gtest.h>
 #include <entt/core/type_traits.hpp>
 #include <entt/meta/meta.hpp>
+#include <entt/meta/policy.hpp>
 #include <entt/meta/resolve.hpp>
 #include <entt/meta/utility.hpp>
 #include "../../common/config.h"
@@ -58,20 +59,22 @@ using MetaUtilityDeathTest = MetaUtility;
 TEST_F(MetaUtility, MetaDispatch) {
     int value = 2;
 
-    auto as_ref = entt::meta_dispatch(value);
-    auto as_cref = entt::meta_dispatch(std::as_const(value));
-    auto as_copy = entt::meta_dispatch(static_cast<int &&>(value));
+    auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
+    auto as_ref = entt::meta_dispatch<entt::as_ref_t>(value);
+    auto as_cref = entt::meta_dispatch<entt::as_cref_t>(value);
+    auto as_is = entt::meta_dispatch(value);
 
+    ASSERT_EQ(as_void.type(), entt::resolve<void>());
     ASSERT_EQ(as_ref.type(), entt::resolve<int>());
     ASSERT_EQ(as_cref.type(), entt::resolve<int>());
-    ASSERT_EQ(as_copy.type(), entt::resolve<int>());
+    ASSERT_EQ(as_is.type(), entt::resolve<int>());
 
-    ASSERT_NE(as_copy.try_cast<int>(), nullptr);
+    ASSERT_NE(as_is.try_cast<int>(), nullptr);
     ASSERT_NE(as_ref.try_cast<int>(), nullptr);
     ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
     ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
 
-    ASSERT_EQ(as_copy.cast<int>(), 2);
+    ASSERT_EQ(as_is.cast<int>(), 2);
     ASSERT_EQ(as_ref.cast<int>(), 2);
     ASSERT_EQ(as_cref.cast<int>(), 2);
 }

+ 3 - 2
test/example/entity_copy.cpp

@@ -5,6 +5,7 @@
 #include <entt/entity/storage.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
+#include <entt/meta/policy.hpp>
 #include <entt/meta/resolve.hpp>
 
 enum class my_entity : entt::id_type {};
@@ -30,9 +31,9 @@ meta_mixin<Type>::meta_mixin(const allocator_type &allocator)
 
     entt::meta_factory<element_type>{}
         // cross registry, same type
-        .template func<entt::overload<entt::storage_for_t<element_type, entt::entity> &(const entt::id_type)>(&entt::basic_registry<entt::entity>::storage<element_type>)>("storage"_hs)
+        .template func<entt::overload<entt::storage_for_t<element_type, entt::entity> &(const entt::id_type)>(&entt::basic_registry<entt::entity>::storage<element_type>), entt::as_ref_t>("storage"_hs)
         // cross registry, different types
-        .template func<entt::overload<entt::storage_for_t<element_type, my_entity> &(const entt::id_type)>(&entt::basic_registry<my_entity>::storage<element_type>)>("storage"_hs);
+        .template func<entt::overload<entt::storage_for_t<element_type, my_entity> &(const entt::id_type)>(&entt::basic_registry<my_entity>::storage<element_type>), entt::as_ref_t>("storage"_hs);
 }
 
 template<typename Type>