From 00b6a53f7e413b710437ea70710571487615fcce Mon Sep 17 00:00:00 2001
From: Antony Polukhin polymorphic_cast
and
polymorphic_downcast
function templates designed to complement the C++ built-in casts.
The header boost/polymorphic_pointer_cast.hpp provides
- polymorphic_pointer_downcast
function template.
+ polymorphic_pointer_cast
and
+ polymorphic_pointer_downcast
function templates.
The program cast_test.cpp can be used to verify these function templates work as expected.
@@ -79,7 +80,7 @@ Warning: Becausepolymorphic_downcast
uses assert(), it
violates the One Definition Rule (ODR) if NDEBUG is inconsistently
defined across translation units. [See ISO Std 3.2]
-+
For crosscasts, or when the success of a cast can only be known at
runtime, or when efficiency is not important,
polymorphic_cast
is preferred.
While polymorphic_downcast
works with built-in pointer types only,
- polymorphic_pointer_downcast
is a more generic version
+
While polymorphic_downcast
and polymorphic_cast
work with built-in pointer types only,
+ polymorphic_pointer_downcast
and polymorphic_pointer_cast
are more generic versions
with support for any pointer type for which the following expressions would be valid:
- static_pointer_cast<Derived>(p);
dynamic_pointer_cast<Derived>(p);
- This includes C++ built-in pointers, std::shared_ptr, boost::shared_ptr, boost::intrusive_ptr
, etc.
For polymorphic_pointer_downcast
:
static_pointer_cast<Derived>(p);
dynamic_pointer_cast<Derived>(p);
For polymorphic_pointer_cast
:
dynamic_pointer_cast<Derived>(p);
!p; // conversion to bool with negation
This includes C++ built-in pointers, std::shared_ptr, boost::shared_ptr, boost::intrusive_ptr
, etc.
namespace boost { @@ -110,6 +116,11 @@ inline Derived polymorphic_downcast(Base* x); // Effects: assert( dynamic_cast<Derived>(x) == x ); // Returns: static_cast<Derived>(x) +template <class Derived, class Base> +inline Derived polymorphic_pointer_cast(Base* x); +// Throws: std::bad_cast if ( dynamic_pointer_cast<Derived>(x) == 0 ) +// Returns: dynamic_pointer_cast<Derived>(x) + template <class Derived, class Base> inline auto polymorphic_pointer_downcast(Base x); // Effects: assert( dynamic_pointer_cast<Derived>(x) == x ); @@ -165,7 +176,8 @@ void f(FruitPtr fruit)polymorphic_downcast
was contributed by Dave Abrahams.
polymorphic_pointer_downcast
was contributed by Boris Rasin.
+ "http://www.boost.org/people/boris_rasin.htm">Boris Rasin and +polymorphic_pointer_cast
by Antony Polukhin.
An oldnumeric_cast
that was contributed by Kevlin Henney is now superseeded by the Boost Numeric Conversion Library diff --git a/include/boost/polymorphic_pointer_cast.hpp b/include/boost/polymorphic_pointer_cast.hpp index bcf6d0f..4d9b46c 100644 --- a/include/boost/polymorphic_pointer_cast.hpp +++ b/include/boost/polymorphic_pointer_cast.hpp @@ -1,5 +1,5 @@ // boost polymorphic_pointer_cast.hpp header file ----------------------------------------------// -// (C) Copyright Boris Rasin 2014. +// (C) Copyright Boris Rasin and Antony Polukhin 2014. // Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -61,6 +61,17 @@ namespace boost return static_pointer_cast(x); } + template + inline typename detail::static_pointer_cast_result ::type + polymorphic_pointer_cast (const Source& x) + { + typename detail::static_pointer_cast_result ::type tmp + = dynamic_pointer_cast (x); + if ( !tmp ) boost::throw_exception( std::bad_cast() ); + + return tmp; + } + } // namespace boost #endif // BOOST_CONVERSION_POLYMORPHIC_POINTER_CAST_HPP diff --git a/test/polymorphic_cast_test.cpp b/test/polymorphic_cast_test.cpp index 9a11068..db44850 100644 --- a/test/polymorphic_cast_test.cpp +++ b/test/polymorphic_cast_test.cpp @@ -1,10 +1,11 @@ // -// Test boost::polymorphic_cast, boost::polymorphic_downcast +// Test boost::polymorphic_cast, boost::polymorphic_downcast and +// boost::polymorphic_pointer_cast, boost::polymorphic_pointer_downcast // // Copyright 1999 Beman Dawes // Copyright 1999 Dave Abrahams // Copyright 2014 Peter Dimov -// Copyright 2014 Boris Rasin +// Copyright 2014 Boris Rasin, Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. // @@ -103,6 +104,67 @@ static void test_polymorphic_cast() delete base; } +static void test_polymorphic_pointer_cast() +{ + Base * base = new Derived; + + Derived * derived; + + try + { + derived = boost::polymorphic_pointer_cast ( base ); + + BOOST_TEST( derived != 0 ); + + if( derived != 0 ) + { + BOOST_TEST_EQ( derived->kind(), "Derived" ); + } + } + catch( std::bad_cast const& ) + { + BOOST_ERROR( "boost::polymorphic_pointer_cast ( base ) threw std::bad_cast" ); + } + + Base2 * base2; + + try + { + base2 = boost::polymorphic_pointer_cast ( base ); // crosscast + + BOOST_TEST( base2 != 0 ); + + if( base2 != 0 ) + { + BOOST_TEST_EQ( base2->kind2(), "Base2" ); + } + } + catch( std::bad_cast const& ) + { + BOOST_ERROR( "boost::polymorphic_pointer_cast ( base ) threw std::bad_cast" ); + } + + boost::shared_ptr sp_base( base ); + boost::shared_ptr sp_base2; + try + { + sp_base2 = boost::polymorphic_pointer_cast ( sp_base ); // crosscast + + BOOST_TEST( sp_base2 != 0 ); + + if( sp_base2 != 0 ) + { + BOOST_TEST_EQ( base2->kind2(), "Base2" ); + } + } + catch( std::bad_cast const& ) + { + BOOST_ERROR( "boost::polymorphic_pointer_cast ( sp_base ) threw std::bad_cast" ); + } + + // we do not `delete base;` because sahred_ptr is holding base +} + static void test_polymorphic_downcast() { Base * base = new Derived; @@ -194,6 +256,21 @@ static void test_polymorphic_cast_fail() delete base; } +static void test_polymorphic_pointer_cast_fail() +{ + Base * base = new Base; + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast ( base ), std::bad_cast ); + delete base; + + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast ( boost::shared_ptr (new Base) ), std::bad_cast ); + +#ifndef BOOST_NO_CXX11_SMART_PTR + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast ( std::shared_ptr (new Base) ), std::bad_cast ); +#endif + + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast ( boost::intrusive_ptr (new Base) ), std::bad_cast ); +} + static void test_polymorphic_downcast_fail() { Base * base = new Base; @@ -270,11 +347,13 @@ static void test_polymorphic_pointer_downcast_intrusive_fail() int main() { test_polymorphic_cast(); + test_polymorphic_pointer_cast(); test_polymorphic_downcast(); test_polymorphic_pointer_downcast_builtin(); test_polymorphic_pointer_downcast_boost_shared(); test_polymorphic_pointer_downcast_intrusive(); test_polymorphic_cast_fail(); + test_polymorphic_pointer_cast_fail(); test_polymorphic_downcast_fail(); test_polymorphic_pointer_downcast_builtin_fail(); test_polymorphic_pointer_downcast_boost_shared_fail();