Skip to content

Commit

Permalink
added possibility to convert raw nullptr pointers in variant to base …
Browse files Browse the repository at this point in the history
…types

I.e. with nullptr's only a downcast is possible, not an upcast.

Fiexe #59
  • Loading branch information
acki-m committed May 17, 2017
1 parent 0fb965d commit e90ece4
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/rttr/detail/type/type_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,14 @@ RTTR_INLINE bool type::is_derived_from() const RTTR_NOEXCEPT

/////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
RTTR_INLINE bool type::is_base_of() const RTTR_NOEXCEPT
{
return is_base_of(type::get<T>());
}

/////////////////////////////////////////////////////////////////////////////////////////

template<typename F>
RTTR_INLINE void type::register_converter_func(F func)
{
Expand Down
20 changes: 17 additions & 3 deletions src/rttr/detail/variant/variant_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,24 @@ RTTR_INLINE variant::try_pointer_conversion(T& to, const type& source_type, cons
if (!source_type.is_pointer())
return false;

if (void * ptr = type::apply_offset(get_raw_ptr(), source_type, target_type))
auto ptr = get_raw_ptr();

if (ptr)
{
if (ptr = type::apply_offset(ptr, source_type, target_type))
{
to = reinterpret_cast<T>(ptr);
return true;
}
}
else // a nullptr
{
to = reinterpret_cast<T>(ptr);
return true;
// check if a down cast is possible
if (source_type.is_derived_from(target_type))
{
to = reinterpret_cast<T>(ptr);
return true;
}
}

return false;
Expand Down
21 changes: 21 additions & 0 deletions src/rttr/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ bool type::is_derived_from(const type& other) const RTTR_NOEXCEPT

/////////////////////////////////////////////////////////////////////////////////////////

bool type::is_base_of(const type& other) const RTTR_NOEXCEPT
{
auto& src_raw_type = m_type_data->raw_type_data;
auto& tgt_raw_type = other.m_type_data->raw_type_data;

if (src_raw_type == tgt_raw_type)
return true;

for (auto& t : src_raw_type->get_class_data().m_derived_types)
{
if (t.m_type_data == tgt_raw_type)
{
return true;
}
}

return false;
}

/////////////////////////////////////////////////////////////////////////////////////////

void* type::apply_offset(void* ptr, const type& source_type, const type& target_type) RTTR_NOEXCEPT
{
auto& src_raw_type = source_type.m_type_data->raw_type_data;
Expand Down
23 changes: 23 additions & 0 deletions src/rttr/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,29 @@ class RTTR_API type
template<typename T>
bool is_derived_from() const RTTR_NOEXCEPT;

/*!
* \brief Returns true if this type is the base class from the given type \p other, otherwise false.
*
* \remark Make sure that the complete class hierarchy has the macro RTTR_ENABLE
* inside the class declaration, otherwise the returned information of this function
* is **not correct**.
*
* \return Returns true if this type is a base class type from \p other, otherwise false.
*/
bool is_base_of(const type& other) const RTTR_NOEXCEPT;

/*!
* \brief Returns true if this type is the base class from the given type \a T, otherwise false.
*
* \remark Make sure that the complete class hierarchy has the macro RTTR_ENABLE
* inside the class declaration, otherwise the returned information of this function
* is **not correct**.
*
* \return Returns true if this type is a base class type from \a T, otherwise false.
*/
template<typename T>
bool is_base_of() const RTTR_NOEXCEPT;

/*!
* \brief Returns a range of all base classes of this type.
*
Expand Down
6 changes: 6 additions & 0 deletions src/unit_tests/variant/variant_conv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,12 @@ TEST_CASE("variant test - convert internal", "[variant]")
CHECK(var.is_type<derived*>() == true);
CHECK(var.get_value<derived*>() == d);
CHECK(var.convert<base*>() == b);

derived* d2 = nullptr;
var = d2;
could_convert = false;
CHECK(var.convert<base*>(&could_convert) == nullptr);
CHECK(could_convert == true);
}

/////////////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit e90ece4

Please sign in to comment.