forked from boostorg/conversion
Merge pull request #6 from Boris-Rasin/polymorphic_pointer_downcast
Add polymorphic_pointer_downcast function template (pull request #2) Looks really good. I'll move your implementation into a separate polymorphic_pointer_cast.hpp header to avoid Typeof dependencies for users that do not use `polymorphic_pointer_downcast`
This commit is contained in:
52
cast.htm
52
cast.htm
@@ -26,10 +26,11 @@
|
||||
|
||||
<h2><a name="Cast Functions">Cast Functions</a></h2>
|
||||
|
||||
<p>The header <a href="../../boost/polymorphic_cast.hpp">boost/polymorphic_cast.hpp</a> provides <code>
|
||||
<a href="#Polymorphic_cast">polymorphic_cast</a> and</code> <a href=
|
||||
"#Polymorphic_cast"><code>polymorphic_downcast</code></a> function templates designed to
|
||||
complement the C++ built-in casts.</p>
|
||||
<p>The header <a href="../../boost/polymorphic_cast.hpp">boost/polymorphic_cast.hpp</a> provides
|
||||
<code><a href="#Polymorphic_cast">polymorphic_cast</a></code>,
|
||||
<code><a href="#Polymorphic_cast">polymorphic_downcast</a></code> and
|
||||
<code><a href="#Polymorphic_cast">polymorphic_pointer_downcast</a></code>
|
||||
function templates designed to complement the C++ built-in casts.</p>
|
||||
|
||||
<p>The program <a href="test/cast_test.cpp">cast_test.cpp</a> can be used to
|
||||
verify these function templates work as expected.</p>
|
||||
@@ -88,7 +89,13 @@
|
||||
whether a given interface is supported; in that case a return of 0 isn't
|
||||
an error condition.</p>
|
||||
|
||||
<h3>polymorphic_cast and polymorphic_downcast synopsis</h3>
|
||||
<p>While <code>polymorphic_downcast</code> works with built-in pointer types only,
|
||||
<code>polymorphic_pointer_downcast</code> is a more generic version
|
||||
with support for any pointer type for which the following expressions would be valid:<br><br>
|
||||
<code> static_pointer_cast<Derived>(p);<br> dynamic_pointer_cast<Derived>(p);</code><br><br>
|
||||
This includes C++ built-in pointers, <code>std::shared_ptr, boost::shared_ptr, boost::intrusive_ptr</code>, etc.</p>
|
||||
|
||||
<h3>polymorphic_cast, polymorphic_downcast and polymorphic_pointer_downcast synopsis</h3>
|
||||
|
||||
<blockquote>
|
||||
<pre>namespace boost {
|
||||
@@ -103,6 +110,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 auto polymorphic_pointer_downcast(Base x);
|
||||
// Effects: assert( dynamic_pointer_cast<Derived>(x) == x );
|
||||
// Returns: static_pointer_cast<Derived>(x)
|
||||
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
@@ -122,14 +134,40 @@ void f( Fruit * fruit ) {
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>polymorphic_pointer_downcast example</h3>
|
||||
|
||||
<blockquote>
|
||||
<pre>#include <boost/polymorphic_cast.hpp>
|
||||
|
||||
class Fruit { public: virtual ~Fruit(){} };
|
||||
class Banana : public Fruit {};
|
||||
|
||||
// use one of these:
|
||||
|
||||
typedef Fruit* FruitPtr;
|
||||
typedef std::shared_ptr<Fruit> FruitPtr;
|
||||
typedef boost::shared_ptr<Fruit> FruitPtr;
|
||||
typedef boost::intrusive_ptr<Fruit> FruitPtr;
|
||||
|
||||
void f(FruitPtr fruit)
|
||||
{
|
||||
// ... logic which leads us to believe it is a banana
|
||||
auto banana = boost::polymorphic_pointer_downcast<Banana>(fruit);
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>History</h3>
|
||||
|
||||
<p><code>polymorphic_cast</code> was suggested by Bjarne Stroustrup in "The C++
|
||||
Programming Language".<br>
|
||||
<code>polymorphic_downcast</code> was contributed by <a href=
|
||||
"http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>.<code><br>
|
||||
"http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>.<br>
|
||||
<code>polymorphic_pointer_downcast</code> was contributed by <a href=
|
||||
"http://www.boost.org/people/boris_rasin.htm">Boris Rasin</a>.<br>
|
||||
An old
|
||||
numeric_cast</code> that was contributed by <a href=
|
||||
<code>numeric_cast</code> that was contributed by <a href=
|
||||
"http://www.boost.org/people/kevlin_henney.htm">Kevlin Henney</a> is now superseeded by the <a href="../numeric/conversion/doc/html/index.html">Boost Numeric Conversion Library</a></p>
|
||||
<hr>
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// boost polymorphic_cast.hpp header file ----------------------------------------------//
|
||||
|
||||
// (C) Copyright Kevlin Henney and Dave Abrahams 1999.
|
||||
// (C) Copyright Boris Rasin 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)
|
||||
@@ -8,6 +9,7 @@
|
||||
// See http://www.boost.org/libs/conversion for Documentation.
|
||||
|
||||
// Revision History
|
||||
// 08 Nov 14 Add polymorphic_pointer_downcast (Boris Rasin)
|
||||
// 09 Jun 14 "cast.hpp" was renamed to "polymorphic_cast.hpp" and
|
||||
// inclusion of numeric_cast was removed (Antony Polukhin)
|
||||
// 23 Jun 05 numeric_cast removed and redirected to the new verion (Fernando Cacciola)
|
||||
@@ -47,6 +49,9 @@
|
||||
|
||||
# include <boost/config.hpp>
|
||||
# include <boost/assert.hpp>
|
||||
# include <boost/pointer_cast.hpp>
|
||||
# include <boost/utility/declval.hpp>
|
||||
# include <boost/typeof/typeof.hpp>
|
||||
# include <typeinfo>
|
||||
|
||||
namespace boost
|
||||
@@ -86,6 +91,41 @@ namespace boost
|
||||
return static_cast<Target>(x);
|
||||
}
|
||||
|
||||
// polymorphic_pointer_downcast --------------------------------------------//
|
||||
|
||||
// BOOST_ASSERT() checked polymorphic downcast. Crosscasts prohibited.
|
||||
// Supports any type with static_pointer_cast/dynamic_pointer_cast functions:
|
||||
// built-in pointers, std::shared_ptr, boost::shared_ptr, boost::intrusive_ptr, etc.
|
||||
|
||||
// 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 Boris Rasin
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Target, typename Source>
|
||||
struct static_pointer_cast_result
|
||||
{
|
||||
#ifdef BOOST_NO_CXX11_DECLTYPE
|
||||
BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, static_pointer_cast<Target>(boost::declval<Source>()))
|
||||
typedef typename nested::type type;
|
||||
#else
|
||||
typedef decltype(static_pointer_cast<Target>(boost::declval<Source>())) type;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Target, typename Source>
|
||||
inline typename detail::static_pointer_cast_result<Target, Source>::type
|
||||
polymorphic_pointer_downcast (const Source& x)
|
||||
{
|
||||
BOOST_ASSERT(dynamic_pointer_cast<Target> (x) == x);
|
||||
return static_pointer_cast<Target> (x);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_POLYMORPHIC_CAST_HPP
|
||||
|
@@ -27,8 +27,8 @@ Standard's built-in casts.</p>
|
||||
Conversion Library is
|
||||
supplied by several headers:</p>
|
||||
<ul>
|
||||
<li>The <a href="cast.htm">boost/cast</a> header provides <b>polymorphic_cast<></b>
|
||||
and <b>polymorphic_downcast<></b> to perform safe casting between
|
||||
<li>The <a href="cast.htm">boost/cast</a> header provides <b>polymorphic_cast<></b>,
|
||||
<b>polymorphic_downcast<></b> and <b>polymorphic_pointer_downcast<></b> to perform safe casting between
|
||||
polymorphic types.<br>
|
||||
</li>
|
||||
<li>The <a href="../../doc/html/boost_lexical_cast.html">boost/lexical_cast</a> header provides <b>lexical_cast<></b>
|
||||
|
@@ -4,6 +4,7 @@
|
||||
// Copyright 1999 Beman Dawes
|
||||
// Copyright 1999 Dave Abrahams
|
||||
// Copyright 2014 Peter Dimov
|
||||
// Copyright 2014 Boris Rasin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
//
|
||||
@@ -12,8 +13,12 @@
|
||||
|
||||
#define BOOST_ENABLE_ASSERT_HANDLER
|
||||
#include <boost/polymorphic_cast.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
static bool expect_assertion = false;
|
||||
static int assertion_failed_count = 0;
|
||||
@@ -37,7 +42,7 @@ void boost::assertion_failed( char const * expr, char const * function, char con
|
||||
|
||||
//
|
||||
|
||||
struct Base
|
||||
struct Base : boost::intrusive_ref_counter<Base>
|
||||
{
|
||||
virtual ~Base() {}
|
||||
virtual std::string kind() { return "Base"; }
|
||||
@@ -115,6 +120,70 @@ static void test_polymorphic_downcast()
|
||||
delete base;
|
||||
}
|
||||
|
||||
static void test_polymorphic_pointer_downcast_builtin()
|
||||
{
|
||||
Base * base = new Derived;
|
||||
|
||||
Derived * derived = boost::polymorphic_pointer_downcast<Derived>( base );
|
||||
|
||||
BOOST_TEST( derived != 0 );
|
||||
|
||||
if( derived != 0 )
|
||||
{
|
||||
BOOST_TEST_EQ( derived->kind(), "Derived" );
|
||||
}
|
||||
|
||||
// polymorphic_pointer_downcast can't do crosscasts
|
||||
|
||||
delete base;
|
||||
}
|
||||
|
||||
static void test_polymorphic_pointer_downcast_boost_shared()
|
||||
{
|
||||
boost::shared_ptr<Base> base (new Derived);
|
||||
|
||||
boost::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
|
||||
|
||||
BOOST_TEST( derived != 0 );
|
||||
|
||||
if( derived != 0 )
|
||||
{
|
||||
BOOST_TEST_EQ( derived->kind(), "Derived" );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_polymorphic_pointer_downcast_intrusive()
|
||||
{
|
||||
boost::intrusive_ptr<Base> base (new Derived);
|
||||
|
||||
boost::intrusive_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
|
||||
|
||||
BOOST_TEST( derived != 0 );
|
||||
|
||||
if( derived != 0 )
|
||||
{
|
||||
BOOST_TEST_EQ( derived->kind(), "Derived" );
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
static void test_polymorphic_pointer_downcast_std_shared()
|
||||
{
|
||||
std::shared_ptr<Base> base (new Derived);
|
||||
|
||||
std::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
|
||||
|
||||
BOOST_TEST( derived != 0 );
|
||||
|
||||
if( derived != 0 )
|
||||
{
|
||||
BOOST_TEST_EQ( derived->kind(), "Derived" );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void test_polymorphic_cast_fail()
|
||||
{
|
||||
Base * base = new Base;
|
||||
@@ -139,12 +208,81 @@ static void test_polymorphic_downcast_fail()
|
||||
delete base;
|
||||
}
|
||||
|
||||
static void test_polymorphic_pointer_downcast_builtin_fail()
|
||||
{
|
||||
Base * base = new Base;
|
||||
|
||||
int old_count = assertion_failed_count;
|
||||
expect_assertion = true;
|
||||
|
||||
boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
|
||||
|
||||
BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
|
||||
expect_assertion = false;
|
||||
|
||||
delete base;
|
||||
}
|
||||
|
||||
static void test_polymorphic_pointer_downcast_boost_shared_fail()
|
||||
{
|
||||
boost::shared_ptr<Base> base (new Base);
|
||||
|
||||
int old_count = assertion_failed_count;
|
||||
expect_assertion = true;
|
||||
|
||||
boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
|
||||
|
||||
BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
|
||||
expect_assertion = false;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
static void test_polymorphic_pointer_downcast_std_shared_fail()
|
||||
{
|
||||
std::shared_ptr<Base> base (new Base);
|
||||
|
||||
int old_count = assertion_failed_count;
|
||||
expect_assertion = true;
|
||||
|
||||
boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
|
||||
|
||||
BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
|
||||
expect_assertion = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void test_polymorphic_pointer_downcast_intrusive_fail()
|
||||
{
|
||||
boost::intrusive_ptr<Base> base (new Base);
|
||||
|
||||
int old_count = assertion_failed_count;
|
||||
expect_assertion = true;
|
||||
|
||||
boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
|
||||
|
||||
BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
|
||||
expect_assertion = false;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_polymorphic_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_downcast_fail();
|
||||
test_polymorphic_pointer_downcast_builtin_fail();
|
||||
test_polymorphic_pointer_downcast_boost_shared_fail();
|
||||
test_polymorphic_pointer_downcast_intrusive_fail();
|
||||
|
||||
#ifndef BOOST_NO_CXX11_SMART_PTR
|
||||
test_polymorphic_pointer_downcast_std_shared();
|
||||
test_polymorphic_pointer_downcast_std_shared_fail();
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
Reference in New Issue
Block a user