diff --git a/examples/runtime_cast.cpp b/examples/runtime_cast.cpp index f359d51..73125b6 100644 --- a/examples/runtime_cast.cpp +++ b/examples/runtime_cast.cpp @@ -45,32 +45,44 @@ int main() { C c; A* a = &c; - if(C* cp = boost::typeindex::runtime_cast(a)) - std::cout << "Yes, a points to a C." << '\n'; - else + if(C* cp = boost::typeindex::runtime_cast(a)) { + std::cout << "Yes, a points to a C: " + << a << "->" << cp << '\n'; + } + else { std::cout << "Error: Expected a to point to a C" << '\n'; + } - if(E* ce = boost::typeindex::runtime_cast(a)) - std::cout << "Error: Expected a to not points to an E." << '\n'; - else + if(E* ce = boost::typeindex::runtime_cast(a)) { + std::cout << "Error: Expected a to not points to an E: " + << a << "->" << ce << '\n'; + } + else { std::cout << "But, a does not point to an E" << '\n'; + } E e; - C* cp = &e; - if(D* dp = boost::typeindex::runtime_cast(cp)) - std::cout << "Yes, we can cross-cast from a C* to a D* when we actually have an E." << '\n'; - else + C* cp2 = &e; + if(D* dp = boost::typeindex::runtime_cast(cp2)) { + std::cout << "Yes, we can cross-cast from a C* to a D* when we actually have an E: " + << cp2 << "->" << dp << '\n'; + } + else { std::cout << "Error: Expected cp to point to a D" << '\n'; + } /*` Alternatively, we can use runtime_pointer_cast so we don't need to specity the target as a pointer. This works for smart_ptr types too. */ A* ap = &e; - if(B* bp = boost::typeindex::runtime_pointer_cast(ap)) - std::cout << "Yes, we can cross-cast and up-cast at the same time." << '\n'; - else + if(B* bp = boost::typeindex::runtime_pointer_cast(ap)) { + std::cout << "Yes, we can cross-cast and up-cast at the same time." + << ap << "->" << bp << '\n'; + } + else { std::cout << "Error: Expected ap to point to a B" << '\n'; + } return 0; } diff --git a/include/boost/type_index/runtime_cast/reference_cast.hpp b/include/boost/type_index/runtime_cast/reference_cast.hpp index f814547..6f30b50 100644 --- a/include/boost/type_index/runtime_cast/reference_cast.hpp +++ b/include/boost/type_index/runtime_cast/reference_cast.hpp @@ -13,11 +13,11 @@ /// \brief Contains the overload of boost::typeindex::runtime_cast for /// reference types. +#include #include #include #include #include -#include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -25,17 +25,23 @@ namespace boost { namespace typeindex { +/// \brief Indicates that runtime_cast was unable to perform the desired cast operation +/// because the source instance was not also an instance of the target type. +struct bad_runtime_cast : std::exception +{}; + /// \brief Safely converts references to classes up, down, and sideways along the inheritance hierarchy. /// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type. /// \tparam U A complete class type of the source instance, u. /// \return If there exists a valid conversion from U& to T, returns a T that references an address -/// suitably offset from u. If no such conversion exists, throws std::bad_cast() +/// suitably offset from u. If no such conversion exists, throws boost::typeindex::bad_runtime_cast. template T& runtime_cast(U& u) { typedef typename boost::remove_reference::type impl_type; - impl_type* value = detail::runtime_cast_impl(&u, boost::is_base_and_derived()); + impl_type* value = detail::runtime_cast_impl( + boost::addressof(u), boost::is_base_and_derived()); if(!value) - boost::throw_exception(std::bad_cast()); + BOOST_THROW_EXCEPTION(bad_runtime_cast()); return *value; } @@ -43,13 +49,14 @@ T& runtime_cast(U& u) { /// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type. /// \tparam U A complete class type of the source instance, u. /// \return If there exists a valid conversion from U const& to T const, returns a T const that references an address -/// suitably offset from u. If no such conversion exists, throws std::bad_cast() +/// suitably offset from u. If no such conversion exists, throws boost::typeindex::bad_runtime_cast. template T const& runtime_cast(U const& u) { typedef typename boost::remove_reference::type impl_type; - impl_type* value = detail::runtime_cast_impl(&u, boost::is_base_and_derived()); + impl_type* value = detail::runtime_cast_impl( + boost::addressof(u), boost::is_base_and_derived()); if(!value) - boost::throw_exception(std::bad_cast()); + BOOST_THROW_EXCEPTION(bad_runtime_cast()); return *value; } diff --git a/test/type_index_runtime_cast_test.cpp b/test/type_index_runtime_cast_test.cpp index 2bf5b9d..56ebe71 100644 --- a/test/type_index_runtime_cast_test.cpp +++ b/test/type_index_runtime_cast_test.cpp @@ -100,13 +100,13 @@ void no_base() using namespace boost::typeindex; base b; base* b2 = runtime_pointer_cast(&b); - BOOST_TEST_NE(b2, (base*)nullptr); + BOOST_TEST_NE(b2, (base*)NULL); BOOST_TEST_EQ(b2->name, "base"); - BOOST_TEST_EQ(runtime_pointer_cast(&b), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(&b), (single_derived*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(&b), (unrelatedV1*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(&b), (unrelated_with_base*)nullptr); + BOOST_TEST_EQ(runtime_pointer_cast(&b), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(&b), (single_derived*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(&b), (unrelatedV1*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(&b), (unrelated_with_base*)NULL); } void single_base() @@ -115,12 +115,12 @@ void single_base() single_derived d; base* b = &d; single_derived* d2 = runtime_pointer_cast(b); - BOOST_TEST_NE(d2, (single_derived*)nullptr); + BOOST_TEST_NE(d2, (single_derived*)NULL); BOOST_TEST_EQ(d2->name, "single_derived"); - BOOST_TEST_EQ(runtime_pointer_cast(&d), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated_with_base*)nullptr); + BOOST_TEST_EQ(runtime_pointer_cast(&d), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated_with_base*)NULL); } void multiple_base() @@ -129,16 +129,16 @@ void multiple_base() multiple_derived d; base1* b1 = &d; multiple_derived* d2 = runtime_pointer_cast(b1); - BOOST_TEST_NE(d2, (multiple_derived*)nullptr); + BOOST_TEST_NE(d2, (multiple_derived*)NULL); BOOST_TEST_EQ(d2->name, "multiple_derived"); base2* b2 = runtime_pointer_cast(b1); - BOOST_TEST_NE(b2, (base2*)nullptr); + BOOST_TEST_NE(b2, (base2*)NULL); BOOST_TEST_EQ(b2->name, "base2"); - BOOST_TEST_EQ(runtime_pointer_cast(&d), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(b1), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(b1), (unrelated_with_base*)nullptr); + BOOST_TEST_EQ(runtime_pointer_cast(&d), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(b1), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(b1), (unrelated_with_base*)NULL); } void virtual_base() @@ -150,18 +150,18 @@ void virtual_base() baseV1* bv1 = runtime_pointer_cast(b); baseV2* bv2 = runtime_pointer_cast(b); - BOOST_TEST_NE(d2, (multiple_virtual_derived*)nullptr); + BOOST_TEST_NE(d2, (multiple_virtual_derived*)NULL); BOOST_TEST_EQ(d2->name, "multiple_virtual_derived"); - BOOST_TEST_NE(bv1, (baseV1*)nullptr); + BOOST_TEST_NE(bv1, (baseV1*)NULL); BOOST_TEST_EQ(bv1->name, "baseV1"); - BOOST_TEST_NE(bv2, (baseV2*)nullptr); + BOOST_TEST_NE(bv2, (baseV2*)NULL); BOOST_TEST_EQ(bv2->name, "baseV2"); - BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(&d), (unrelated*)nullptr); - BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated_with_base*)nullptr); + BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(&d), (unrelated*)NULL); + BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated_with_base*)NULL); } void pointer_interface() @@ -170,9 +170,9 @@ void pointer_interface() single_derived d; base* b = &d; single_derived* d2 = runtime_cast(b); - BOOST_TEST_NE(d2, (single_derived*)nullptr); + BOOST_TEST_NE(d2, (single_derived*)NULL); BOOST_TEST_EQ(d2->name, "single_derived"); - BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)nullptr); + BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)NULL); } void reference_interface() @@ -186,9 +186,12 @@ void reference_interface() try { unrelated& u = runtime_cast(b); (void)u; - BOOST_TEST(!"should throw bad_cast"); + BOOST_TEST(!"should throw bad_runtime_cast"); + } + catch(boost::typeindex::bad_runtime_cast&) { } catch(...) { + BOOST_TEST(!"should throw bad_runtime_cast"); } } @@ -198,9 +201,9 @@ void const_pointer_interface() const single_derived d; base const* b = &d; single_derived const* d2 = runtime_cast(b); - BOOST_TEST_NE(d2, (single_derived*)nullptr); + BOOST_TEST_NE(d2, (single_derived*)NULL); BOOST_TEST_EQ(d2->name, "single_derived"); - BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)nullptr); + BOOST_TEST_EQ(runtime_pointer_cast(b), (unrelated*)NULL); } void const_reference_interface() @@ -214,9 +217,12 @@ void const_reference_interface() try { unrelated const& u = runtime_cast(b); (void)u; - BOOST_TEST(!"should throw bad_cast"); + BOOST_TEST(!"should throw bad_runtime_cast"); + } + catch(boost::typeindex::bad_runtime_cast&) { } catch(...) { + BOOST_TEST(!"should throw bad_runtime_cast"); } } @@ -228,7 +234,7 @@ void diamond_non_virtual() base* b1 = l1a; level1_b* l1_b = runtime_cast(b1); BOOST_TEST_EQ(l1_b->name, "level1_b"); - BOOST_TEST_NE(l1_b, (level1_b*)nullptr); + BOOST_TEST_NE(l1_b, (level1_b*)NULL); } void boost_shared_ptr()