boost::polymorphic_downcast only supports raw pointer cast, which is a gap compared to static_cast.

To make it clear:
       Base* base = new Base();

       static_cast<Derived*>(base)                 ===> OK
       static_cast<Derived&>(*base)                ===> OK

       boost::polymorphic_downcast<Derived*>(base)  ===> OK
       boost::polymorphic_downcast<Derived&>(*base) ===> IMPOSSIBLE

    boost::polymorphic_downcast being a kind of "debug-safe version" of
    static_cast, it should provide the same capabilities.

    This patch extend boost::polymorphic_downcast to support references just
    like static_cast does.
    This is achieved by introducing a partial specialization for references.
    Unit tests have been updated accordingly.
This commit is contained in:
Julien DELACROIX
2019-12-05 16:20:02 +01:00
parent 9d4a518e74
commit e130cd860c
2 changed files with 52 additions and 15 deletions

View File

@ -52,6 +52,9 @@
# include <boost/config.hpp>
# include <boost/assert.hpp>
# include <boost/throw_exception.hpp>
# include <boost/type_traits/is_reference.hpp>
# include <boost/type_traits/remove_reference.hpp>
# include <boost/utility/enable_if.hpp>
# include <typeinfo>
#ifdef BOOST_HAS_PRAGMA_ONCE
@ -79,7 +82,7 @@ namespace boost
// polymorphic_downcast ----------------------------------------------------//
// BOOST_ASSERT() checked polymorphic downcast. Crosscasts prohibited.
// BOOST_ASSERT() checked raw pointer polymorphic downcast. Crosscasts prohibited.
// WARNING: Because this cast uses BOOST_ASSERT(), it violates
// the One Definition Rule if used in multiple translation units
@ -95,6 +98,22 @@ namespace boost
return static_cast<Target>(x);
}
// BOOST_ASSERT() checked reference polymorphic downcast. Crosscasts prohibited.
// WARNING: Because this cast uses BOOST_ASSERT(), it violates
// the One Definition Rule if used in multiple translation units
// where BOOST_DISABLE_ASSERTS, BOOST_ENABLE_ASSERT_HANDLER
// NDEBUG are defined inconsistently.
// Contributed by Julien Delacroix
template <class Target, class Source>
inline typename boost::enable_if_c<boost::is_reference<Target>::value, Target>::type polymorphic_downcast(Source &x)
{
BOOST_ASSERT(dynamic_cast<typename boost::remove_reference<Target>::type *>(&x) == &x);
return static_cast<Target>(x);
}
} // namespace boost
#endif // BOOST_POLYMORPHIC_CAST_HPP

View File

@ -172,20 +172,23 @@ static void test_polymorphic_pointer_cast()
static void test_polymorphic_downcast()
{
Base * base = new Derived;
Base *base_pointer = new Derived;
Derived * derived = boost::polymorphic_downcast<Derived*>( base );
// test raw pointer cast
Derived *derived_pointer = boost::polymorphic_downcast<Derived *>(base_pointer);
BOOST_TEST( derived != 0 );
BOOST_TEST(derived_pointer != 0);
if( derived != 0 )
if (derived_pointer != 0)
{
BOOST_TEST_EQ( derived->kind(), "Derived" );
BOOST_TEST_EQ(derived_pointer->kind(), "Derived");
}
// polymorphic_downcast can't do crosscasts
// test reference cast
Derived& derived_ref = boost::polymorphic_downcast<Derived&>(*base_pointer);
BOOST_TEST_EQ(derived_ref.kind(), "Derived");
delete base;
delete base_pointer;
}
static void test_polymorphic_pointer_downcast_builtin()
@ -278,17 +281,32 @@ static void test_polymorphic_pointer_cast_fail()
static void test_polymorphic_downcast_fail()
{
Base * base = new Base;
Base * base_pointer = new Base;
int old_count = assertion_failed_count;
expect_assertion = true;
{
// test raw pointer cast
BOOST_TEST_THROWS( boost::polymorphic_downcast<Derived*>( base ), expected_assertion ); // should assert
int old_count = assertion_failed_count;
expect_assertion = true;
BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
expect_assertion = false;
BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived *>(base_pointer), expected_assertion); // should assert
delete base;
BOOST_TEST_EQ(assertion_failed_count, old_count + 1);
expect_assertion = false;
}
{
// test reference cast
int old_count = assertion_failed_count;
expect_assertion = true;
BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived &>(*base_pointer), expected_assertion); // should assert
BOOST_TEST_EQ(assertion_failed_count, old_count + 1);
expect_assertion = false;
}
delete base_pointer;
}
static void test_polymorphic_pointer_downcast_builtin_fail()