meta: as_ref_t adapts to const objects/const-ref return types
This commit is contained in:
@@ -712,33 +712,30 @@ There are a few alternatives available at the moment:
|
||||
|
||||
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
|
||||
Its purpose is to discard the return value of a meta object, whatever it is,
|
||||
thus making it appear as if its type were `void`.<br/>
|
||||
thus making it appear as if its type were `void`:
|
||||
```cpp
|
||||
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
|
||||
```
|
||||
If the use with functions is obvious, it must be said that it's also possible
|
||||
to use this policy with constructors and data members. In the first case, the
|
||||
constructor will be invoked but the returned wrapper will actually be empty.
|
||||
In the second case, instead, the property will not be accessible for reading.
|
||||
|
||||
As an example of use:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
|
||||
```
|
||||
|
||||
* The _as-ref_ and _as-cref_ policies, associated with the types
|
||||
`entt::as_ref_t` and `entt::as_cref_t`.<br/>
|
||||
They allow to build wrappers that act as references to unmanaged objects.
|
||||
Accessing the object contained in the wrapper for which the _reference_ was
|
||||
requested will make it possible to directly access the instance used to
|
||||
initialize the wrapper itself.<br/>
|
||||
These policies work with constructors (for example, when objects are taken
|
||||
from an external container rather than created on demand), data members and
|
||||
functions in general (as long as their return types are lvalue references).
|
||||
|
||||
As an example of use:
|
||||
|
||||
initialize the wrapper itself:
|
||||
```cpp
|
||||
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
|
||||
```
|
||||
These policies work with constructors (for example, when objects are taken
|
||||
from an external container rather than created on demand), data members and
|
||||
functions in general.<br/>
|
||||
If on the one hand `as_cref_t` always forces the return type to be const,
|
||||
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
|
||||
return type if any.
|
||||
|
||||
Some uses are rather trivial, but it's useful to note that there are some less
|
||||
obvious corner cases that can in turn be solved with the use of policies.
|
||||
@@ -763,8 +760,8 @@ Exporting constant values or elements from an enum is as simple as ever:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_enum>()
|
||||
.data<my_enum::a_value>("a_value"_hs)
|
||||
.data<my_enum::another_value>("another_value"_hs);
|
||||
.data<my_enum::a_value>("a_value"_hs)
|
||||
.data<my_enum::another_value>("another_value"_hs);
|
||||
|
||||
entt::meta<int>().data<2048>("max_int"_hs);
|
||||
```
|
||||
|
||||
@@ -123,7 +123,7 @@ template<typename Type, auto Data, typename Policy>
|
||||
if constexpr(std::is_same_v<Policy, as_void_t>) {
|
||||
return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::ref(std::forward<decltype(value)>(value))};
|
||||
return meta_any{std::reference_wrapper{std::forward<decltype(value)>(value)}};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
return meta_any{std::cref(std::forward<decltype(value)>(value))};
|
||||
} else {
|
||||
@@ -139,8 +139,12 @@ template<typename Type, auto Data, typename Policy>
|
||||
if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
|
||||
return meta_any{};
|
||||
} else {
|
||||
auto * const clazz = instance->try_cast<std::conditional_t<std::is_same_v<Policy, as_ref_t>, Type, const Type>>();
|
||||
return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
|
||||
if(auto * clazz = instance->try_cast<Type>(); clazz) {
|
||||
return dispatch(std::invoke(Data, *clazz));
|
||||
} else {
|
||||
auto * fallback = instance->try_cast<const Type>();
|
||||
return fallback ? dispatch(std::invoke(Data, *fallback)) : meta_any{};
|
||||
}
|
||||
}
|
||||
} else if constexpr(std::is_pointer_v<std::decay_t<decltype(Data)>>) {
|
||||
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
|
||||
@@ -163,7 +167,7 @@ template<typename Type, auto Candidate, typename Policy, std::size_t... Index>
|
||||
std::invoke(Candidate, std::forward<decltype(params)>(params)...);
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::ref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
|
||||
return meta_any{std::reference_wrapper{std::invoke(Candidate, std::forward<decltype(params)>(params)...)}};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
return meta_any{std::cref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
|
||||
} else {
|
||||
|
||||
@@ -418,9 +418,15 @@ TEST_F(MetaData, ConstInstance) {
|
||||
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(instance).try_cast<int>(), nullptr);
|
||||
ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(instance).try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)).try_cast<int>(), nullptr);
|
||||
// as_ref_t adapts to the constness of the passed object and returns const references in case
|
||||
ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)).try_cast<const int>(), nullptr);
|
||||
|
||||
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_TRUE(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));
|
||||
|
||||
Reference in New Issue
Block a user