meta: meta_type::from_void support
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
* [Template information](#template-information)
|
||||
* [Automatic conversions](#automatic-conversions)
|
||||
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
|
||||
* [From void to any](#from-void-to-any)
|
||||
* [Policies: the more, the less](#policies-the-more-the-less)
|
||||
* [Named constants and enums](#named-constants-and-enums)
|
||||
* [Properties and meta objects](#properties-and-meta-objects)
|
||||
@@ -783,6 +784,24 @@ useful for building keys without knowing or having to register the actual types.
|
||||
In all cases, when users register default constructors, they are preferred both
|
||||
during searches and when the `construct` member function is invoked.
|
||||
|
||||
## From void to any
|
||||
|
||||
Sometimes all a user has is an opaque pointer to an object of a known meta type.
|
||||
It would be handy in this case to be able to construct a `meta_any` object from
|
||||
them.<br/>
|
||||
For this purpose, the `meta_type` class offers a `from_void` member function
|
||||
designed to convert an opaque pointer into a `meta_any`:
|
||||
|
||||
```cpp
|
||||
entt::meta_any any = entt::resolve(id).from_void(element);
|
||||
```
|
||||
|
||||
It goes without saying that it's not possible to do a check on the actual type.
|
||||
Therefore, this call can be considered as a _static cast_ with all the problems
|
||||
and undefined behaviors of the case following errors.<br/>
|
||||
On the other hand, the ability to construct a `meta_any` from an opaque pointer
|
||||
opens the door to some pretty interesting uses that are worth exploring.
|
||||
|
||||
## Policies: the more, the less
|
||||
|
||||
Policies are a kind of compile-time directives that can be used when registering
|
||||
|
||||
@@ -1231,6 +1231,20 @@ public:
|
||||
return construct(arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wraps an opaque element of the underlying type.
|
||||
* @param element A valid pointer to an element of the underlying type.
|
||||
* @return A wrapper that references the given instance.
|
||||
*/
|
||||
meta_any from_void(void *element) {
|
||||
return node->from_void ? node->from_void(element, nullptr) : meta_any{};
|
||||
}
|
||||
|
||||
/*! @copydoc from_void */
|
||||
meta_any from_void(const void *element) {
|
||||
return node->from_void ? node->from_void(nullptr, element) : meta_any{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invokes a function given an identifier, if possible.
|
||||
*
|
||||
|
||||
@@ -111,6 +111,7 @@ struct meta_type_node {
|
||||
meta_type_node *(*const remove_pointer)() noexcept;
|
||||
meta_any (*const default_constructor)();
|
||||
double (*const conversion_helper)(void *, const void *);
|
||||
meta_any (*const from_void)(void *, const void *);
|
||||
const meta_template_node *const templ;
|
||||
meta_ctor_node *ctor{nullptr};
|
||||
meta_base_node *base{nullptr};
|
||||
@@ -149,6 +150,16 @@ class ENTT_API meta_node {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto *meta_from_void() noexcept {
|
||||
if constexpr(std::is_same_v<Type, void> || std::is_array_v<Type> || std::is_function_v<Type>) {
|
||||
return static_cast<std::decay_t<decltype(meta_type_node::from_void)>>(nullptr);
|
||||
} else {
|
||||
return +[](void *element, const void *as_const) {
|
||||
return element ? meta_any{std::in_place_type<Type &>, *static_cast<Type *>(element)} : meta_any{std::in_place_type<const Type &>, *static_cast<const Type *>(as_const)};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_template_node *meta_template_info() noexcept {
|
||||
if constexpr(is_complete_v<meta_template_traits<Type>>) {
|
||||
static meta_template_node node{
|
||||
@@ -184,6 +195,7 @@ public:
|
||||
&meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
|
||||
meta_default_constructor(),
|
||||
meta_conversion_helper(),
|
||||
meta_from_void(),
|
||||
meta_template_info()
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
@@ -465,6 +465,34 @@ TEST_F(MetaType, ConstructArithmeticConversion) {
|
||||
ASSERT_EQ(any.cast<clazz_t>().value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, FromVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<void *>(nullptr)));
|
||||
ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<const void *>(nullptr)));
|
||||
|
||||
auto type = entt::resolve<double>();
|
||||
double value = 4.2;
|
||||
|
||||
auto as_void = type.from_void(static_cast<void *>(&value));
|
||||
auto as_const_void = type.from_void(static_cast<const void *>(&value));
|
||||
|
||||
ASSERT_TRUE(as_void);
|
||||
ASSERT_TRUE(as_const_void);
|
||||
|
||||
ASSERT_EQ(as_void.type(), entt::resolve<double>());
|
||||
ASSERT_NE(as_void.try_cast<double>(), nullptr);
|
||||
|
||||
ASSERT_EQ(as_const_void.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(as_const_void.try_cast<double>(), nullptr);
|
||||
ASSERT_NE(as_const_void.try_cast<const double>(), nullptr);
|
||||
|
||||
value = 1.2;
|
||||
|
||||
ASSERT_EQ(as_void.cast<double>(), as_const_void.cast<double>());
|
||||
ASSERT_EQ(as_void.cast<double>(), 1.2);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Reset) {
|
||||
using namespace entt::literals;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user