diff --git a/include/boost/type_index/runtime_cast.hpp b/include/boost/type_index/runtime_cast.hpp index 333753d..0221cde 100644 --- a/include/boost/type_index/runtime_cast.hpp +++ b/include/boost/type_index/runtime_cast.hpp @@ -18,7 +18,10 @@ #include #include -#include +#include +#include +#include +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -29,89 +32,72 @@ namespace boost { namespace typeindex { namespace detail { -template -struct find_type { - template - Current* check_current(T* p, type_index const& idx) const BOOST_NOEXCEPT { - if(idx == boost::typeindex::type_id()) - return p; - return nullptr; - } - - template - void* check_bases(T* p, type_index const& idx) const BOOST_NOEXCEPT { - return nullptr; - } - - template - void* check_bases(T* p, type_index const& idx) const BOOST_NOEXCEPT { - if(void* result = p->FirstBase::boost_type_index_find_instance_(idx)) - return result; - return check_bases(p, idx); - } - - template - void* operator()(T* p, type_index const& idx) const BOOST_NOEXCEPT { - if(Current* current = check_current(p, idx)) - return p; - return check_bases(p, idx); - } -}; - template -T* runtime_cast_impl(U* u, std::true_type) { +T* runtime_cast_impl(U* u, boost::true_type) { return u; } template -T const* runtime_cast_impl(U const* u, std::true_type) { +T const* runtime_cast_impl(U const* u, boost::true_type) { return u; } template -T* runtime_cast_impl(U* u, std::false_type) { - return static_cast( +T* runtime_cast_impl(U* u, boost::false_type) { + return const_cast(static_cast( u->boost_type_index_find_instance_(boost::typeindex::type_id()) - ); + )); } template -T const* runtime_cast_impl(U const* u, std::false_type) { - return static_cast( - const_cast(u)->boost_type_index_find_instance_(boost::typeindex::type_id()) - ); +T const* runtime_cast_impl(U const* u, boost::false_type) { + return static_cast(u->boost_type_index_find_instance_(boost::typeindex::type_id())); +} + +template +type_index get_type_for_value(T const&) { + return type_id::type>(); } } // namespace detail -#define BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI \ - virtual void* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) BOOST_NOEXCEPT { \ - if(idx == boost::typeindex::type_id::type>()) \ - return this; \ - return nullptr; \ +#define BOOST_TYPE_INDEX_CHECK_BASE_(r, data, Base) \ + if(void const* ret_val = this->Base::boost_type_index_find_instance_(idx)) return ret_val; + +#define BOOST_TYPE_INDEX_CHECK_BASES(base_list) \ + BOOST_PP_SEQ_FOR_EACH(BOOST_TYPE_INDEX_CHECK_BASE_, _, base_list) + +#define BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI \ + virtual void const* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) const BOOST_NOEXCEPT { \ + if(idx == boost::typeindex::detail::get_type_for_value(*this)) \ + return this; \ + return NULL; \ } -#define BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(...) \ - virtual void* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) BOOST_NOEXCEPT { \ - return boost::typeindex::detail::find_type::type, __VA_ARGS__>()(this, idx);\ +#define BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base_list) \ + virtual void const* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) const BOOST_NOEXCEPT { \ + if(idx == boost::typeindex::detail::get_type_for_value(*this)) \ + return this; \ + BOOST_TYPE_INDEX_CHECK_BASES(base_list) \ + return NULL; \ } template T runtime_cast(U* u) BOOST_NOEXCEPT { - typedef typename std::remove_pointer::type impl_type; - return detail::runtime_cast_impl(u, std::is_same()); + typedef typename boost::remove_pointer::type impl_type; + return detail::runtime_cast_impl(u, boost::is_base_and_derived()); } template T runtime_cast(U const* u) BOOST_NOEXCEPT { - typedef typename std::remove_pointer::type impl_type; - return detail::runtime_cast_impl(u, std::is_same()); + typedef typename boost::remove_pointer::type impl_type; + return detail::runtime_cast_impl(u, boost::is_base_and_derived()); } template T runtime_cast(U& u) { - typedef typename std::remove_reference::type impl_type; - impl_type* value = detail::runtime_cast_impl(&u, std::is_same()); + typedef typename boost::remove_reference::type impl_type; + impl_type* value = detail::runtime_cast_impl(&u, boost::is_base_and_derived()); if(!value) boost::throw_exception(std::bad_cast()); return *value; @@ -119,8 +105,8 @@ T const* runtime_cast_impl(U const* u, std::false_type) { template T runtime_cast(U const& u) { - typedef typename std::remove_reference::type impl_type; - impl_type* value = detail::runtime_cast_impl(&u, std::is_same()); + typedef typename boost::remove_reference::type impl_type; + impl_type* value = detail::runtime_cast_impl(&u, boost::is_base_and_derived()); if(!value) boost::throw_exception(std::bad_cast()); return *value; @@ -128,12 +114,12 @@ T const* runtime_cast_impl(U const* u, std::false_type) { template T* runtime_pointer_cast(U* u) BOOST_NOEXCEPT { - return detail::runtime_cast_impl(u, std::is_same()); + return detail::runtime_cast_impl(u, boost::is_base_and_derived()); } template T const* runtime_pointer_cast(U const* u) BOOST_NOEXCEPT { - return detail::runtime_cast_impl(u, std::is_same()); + return detail::runtime_cast_impl(u, boost::is_base_and_derived()); } }} // namespace boost::typeindex diff --git a/test/runtime_cast_test.cpp b/test/runtime_cast_test.cpp index 970566d..a456eac 100644 --- a/test/runtime_cast_test.cpp +++ b/test/runtime_cast_test.cpp @@ -25,7 +25,7 @@ struct base { }; struct single_derived : base { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) IMPLEMENT_CLASS(single_derived) }; @@ -40,35 +40,53 @@ struct base2 { }; struct multiple_derived : base1, base2 { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base1, base2) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base1)(base2)) IMPLEMENT_CLASS(multiple_derived) }; struct baseV1 : virtual base { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) IMPLEMENT_CLASS(baseV1) }; struct baseV2 : virtual base { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) IMPLEMENT_CLASS(baseV2) }; struct multiple_virtual_derived : baseV1, baseV2 { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(baseV1, baseV2) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((baseV1)(baseV2)) IMPLEMENT_CLASS(multiple_virtual_derived) }; struct unrelated { BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI + IMPLEMENT_CLASS(unrelated) }; struct unrelated_with_base : base { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) + IMPLEMENT_CLASS(unrelated_with_base) }; struct unrelatedV1 : virtual base { - BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES(base) + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) + IMPLEMENT_CLASS(unrelatedV1) +}; + +struct level1_a : base { + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) + IMPLEMENT_CLASS(level1_a) +}; + +struct level1_b : base { + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((base)) + IMPLEMENT_CLASS(level1_b) +}; + +struct level2 : level1_a, level1_b { + BOOST_TYPE_INDEX_REGISTER_CLASS_RTTI_BASES((level1_a)(level1_b)) + IMPLEMENT_CLASS(level2) }; void no_base() @@ -196,6 +214,16 @@ void const_reference_interface() } } +void diamond_non_virtual() +{ + using namespace boost::typeindex; + level2 inst; + level1_a* l1a = &inst; + base* b1 = l1a; + level1_b* l1_b = runtime_cast(b1); + BOOST_TEST_NE(l1_b, (level1_b*)nullptr); +} + int main() { no_base(); single_derived(); @@ -205,6 +233,7 @@ int main() { reference_interface(); const_pointer_interface(); const_reference_interface(); + diamond_non_virtual(); return boost::report_errors(); }