meta: as_auto policy

This commit is contained in:
skypjack
2025-10-28 15:34:45 +01:00
parent d92bea4afd
commit d366a5ed92
7 changed files with 163 additions and 32 deletions

2
TODO
View File

@@ -33,6 +33,6 @@ TODO:
* resource: shared_from_this?
* finish the imgui viewer/editor!
* introduce compile-time flag to skip dll-only checks in basic_any
* auto policy for return types in meta (i.e. it picks as_is or as_(c)ref automatically as needed)
* find a way to test deleter and the absence of it in basic_any
* archetype-like a-là EnTT support (see my own notes)
* rename meta policy as_is in as_copy

View File

@@ -825,6 +825,18 @@ There are a few alternatives available at the moment:
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
return type if any.
* The _as-auto_ policy, associated with the type `entt::as_auto_t`.<br/>
Useful for decoupling meta type creation code from calling code while still
preserving the behavior of data members and member functions as defined:
```cpp
entt::meta_factory<my_type>{}.func<&my_type::any_member, entt::as_auto_t>("member"_hs);
```
For data members or member functions that return a reference type, the value
is returned by reference with the same constness. In all other cases, the
value is returned by copy.
Some uses are rather trivial, but it is useful to note that there are some less
obvious corner cases that can in turn be solved with the use of policies.

View File

@@ -5,24 +5,16 @@
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 */
};
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
/*! @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 */
};
struct meta_policy {};
} // namespace internal
/*! @endcond */
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_is_t final {
struct as_is_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
@@ -30,7 +22,31 @@ struct as_is_t final {
};
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t final {
struct as_void_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t final: private internal::meta_policy {
/*! @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: private internal::meta_policy {
/*! @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 auto_ policy. */
struct as_auto_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
@@ -44,7 +60,7 @@ struct as_void_t final {
*/
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>> {};
: std::bool_constant<std::is_base_of_v<internal::meta_policy, Type>> {};
/**
* @brief Helper variable template.

View File

@@ -166,13 +166,13 @@ using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::t
*/
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>) {
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 if constexpr(std::is_same_v<Policy, as_ref_t> || (std::is_same_v<Policy, as_auto_t> && std::is_lvalue_reference_v<Type>)) {
return meta_any{ctx, std::in_place_type<Type>, value};
} else if constexpr(std::is_same_v<Policy, as_void_t>) {
return meta_any{ctx, std::in_place_type<void>};
} else {
return meta_any{ctx, std::forward<Type>(value)};
}

View File

@@ -97,6 +97,13 @@ struct MetaData: ::testing::Test {
.data<&clazz::i, entt::as_void_t>("void"_hs)
.conv<int>();
entt::meta_factory<clazz>{}
.data<&clazz::i, entt::as_auto_t>("ai"_hs)
.data<&clazz::j, entt::as_auto_t>("aj"_hs)
.data<&clazz::h, entt::as_auto_t>("ah"_hs)
.data<&clazz::k, entt::as_auto_t>("ak"_hs)
.data<nullptr, &clazz::operator int, entt::as_auto_t>("ao"_hs);
entt::meta_factory<setter_getter>{}
.type("setter_getter"_hs)
.data<&setter_getter::static_setter, &setter_getter::static_getter>("x"_hs)
@@ -541,6 +548,44 @@ TEST_F(MetaData, AsVoid) {
ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
}
TEST_F(MetaData, AsAuto) {
using namespace entt::literals;
auto type = entt::resolve<clazz>();
entt::meta_data data{};
clazz instance{};
data = type.data("ai"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::ref);
data = type.data("aj"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::cref);
data = type.data("ah"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::ref);
data = type.data("ak"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::cref);
data = type.data("ao"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::embedded);
}
TEST_F(MetaData, AsRef) {
using namespace entt::literals;

View File

@@ -74,7 +74,7 @@ struct function {
instance.value = iv;
}
[[nodiscard]] int v(int &iv) const {
[[nodiscard]] const int &v(int &iv) const {
return (iv = value);
}
@@ -137,6 +137,12 @@ struct MetaFunc: ::testing::Test {
.func<&function::a, entt::as_ref_t>("a"_hs)
.func<&function::a, entt::as_cref_t>("ca"_hs)
.conv<int>();
entt::meta_factory<function>{}
.func<&function::a, entt::as_auto_t>("aa"_hs)
.func<&function::v, entt::as_auto_t>("av"_hs)
.func<&function::operator int, entt::as_auto_t>("ao"_hs)
.func<&function::g, entt::as_auto_t>("ag"_hs);
}
void TearDown() override {
@@ -503,6 +509,38 @@ TEST_F(MetaFunc, AsVoid) {
ASSERT_EQ(value, instance.value);
}
TEST_F(MetaFunc, AsAuto) {
using namespace entt::literals;
auto type = entt::resolve<function>();
entt::meta_func func{};
function instance{3};
func = type.func("aa"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::ref);
func = type.func("av"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance, 3).base().policy(), entt::any_policy::cref);
func = type.func("ao"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::embedded);
func = type.func("ag"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<void>());
ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::empty);
}
TEST_F(MetaFunc, AsRef) {
using namespace entt::literals;

View File

@@ -59,24 +59,44 @@ using MetaUtilityDeathTest = MetaUtility;
TEST_F(MetaUtility, MetaDispatch) {
int value = 2;
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_ref = entt::meta_dispatch<entt::as_ref_t>(value);
auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
auto as_auto_copy = entt::meta_dispatch<entt::as_auto_t>(static_cast<int &&>(value));
auto as_auto_cref = entt::meta_dispatch<entt::as_auto_t>(std::as_const(value));
auto as_auto_ref = entt::meta_dispatch<entt::as_auto_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_ref.type(), entt::resolve<int>());
ASSERT_EQ(as_void.type(), entt::resolve<void>());
ASSERT_EQ(as_auto_copy.type(), entt::resolve<int>());
ASSERT_EQ(as_auto_cref.type(), entt::resolve<int>());
ASSERT_EQ(as_auto_ref.type(), entt::resolve<int>());
ASSERT_EQ(as_is.type(), entt::resolve<int>());
ASSERT_NE(as_is.try_cast<int>(), nullptr);
ASSERT_NE(as_ref.try_cast<int>(), nullptr);
ASSERT_EQ(as_cref.base().policy(), entt::any_policy::cref);
ASSERT_EQ(as_ref.base().policy(), entt::any_policy::ref);
ASSERT_EQ(as_void.base().policy(), entt::any_policy::empty);
ASSERT_EQ(as_auto_copy.base().policy(), entt::any_policy::embedded);
ASSERT_EQ(as_auto_cref.base().policy(), entt::any_policy::cref);
ASSERT_EQ(as_auto_ref.base().policy(), entt::any_policy::ref);
ASSERT_EQ(as_is.base().policy(), entt::any_policy::embedded);
ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
ASSERT_NE(as_ref.try_cast<int>(), nullptr);
ASSERT_NE(as_auto_copy.try_cast<int>(), nullptr);
ASSERT_EQ(as_auto_cref.try_cast<int>(), nullptr);
ASSERT_NE(as_auto_ref.try_cast<int>(), nullptr);
ASSERT_NE(as_is.try_cast<int>(), nullptr);
ASSERT_EQ(as_is.cast<int>(), 2);
ASSERT_EQ(as_ref.cast<int>(), 2);
ASSERT_EQ(as_cref.cast<int>(), 2);
ASSERT_EQ(as_ref.cast<int>(), 2);
ASSERT_EQ(as_auto_copy.cast<int>(), 2);
ASSERT_EQ(as_auto_cref.cast<int>(), 2);
ASSERT_EQ(as_auto_ref.cast<int>(), 2);
ASSERT_EQ(as_is.cast<int>(), 2);
}
TEST_F(MetaUtility, MetaDispatchMetaAny) {