meta: as_auto policy
This commit is contained in:
2
TODO
2
TODO
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user