diff options
Diffstat (limited to 'libs/conversion')
-rw-r--r-- | libs/conversion/README.md | 16 | ||||
-rw-r--r-- | libs/conversion/cast.htm | 66 | ||||
-rw-r--r-- | libs/conversion/index.html | 8 | ||||
-rw-r--r-- | libs/conversion/test/implicit_cast.cpp | 2 | ||||
-rw-r--r-- | libs/conversion/test/polymorphic_cast_test.cpp | 222 |
5 files changed, 301 insertions, 13 deletions
diff --git a/libs/conversion/README.md b/libs/conversion/README.md new file mode 100644 index 000000000..35f99751a --- /dev/null +++ b/libs/conversion/README.md @@ -0,0 +1,16 @@ +#[Boost.Conversion](http://boost.org/libs/conversion) +Boost.Conversion is one of the [Boost C++ Libraries](http://github.com/boostorg). This library improves program safety and clarity by performing otherwise messy conversions. + +### Test results + +@ | Build | Tests coverage | More info +----------------|-------------- | -------------- |----------- +Develop branch: | [](https://travis-ci.org/apolukhin/conversion) | [](https://coveralls.io/r/apolukhin/conversion?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/conversion.html) +Master branch: | [](https://travis-ci.org/apolukhin/conversion) | [](https://coveralls.io/r/apolukhin/conversion?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/conversion.html) + + +[Open Issues](https://svn.boost.org/trac/boost/query?status=!closed&component=conversion&or&status=!closed&component=lexical_cast) + +### License + +Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt). diff --git a/libs/conversion/cast.htm b/libs/conversion/cast.htm index 208b960f2..e1c466d56 100644 --- a/libs/conversion/cast.htm +++ b/libs/conversion/cast.htm @@ -26,10 +26,12 @@ <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> and + <code><a href="#Polymorphic_cast">polymorphic_downcast</a></code> + function templates designed to complement the C++ built-in casts.</p> <p>The header <a href="../../boost/polymorphic_pointer_cast.hpp">boost/polymorphic_pointer_cast.hpp</a> provides + <code><a href="#Polymorphic_cast">polymorphic_pointer_cast</a></code> and + <code><a href="#Polymorphic_cast">polymorphic_pointer_downcast</a></code> function templates. <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> @@ -78,7 +80,7 @@ <b>Warning:</b> Because <code>polymorphic_downcast</code> uses assert(), it violates the One Definition Rule (ODR) if NDEBUG is inconsistently defined across translation units. [See ISO Std 3.2] -</p><p> + <p> For crosscasts, or when the success of a cast can only be known at runtime, or when efficiency is not important, <code>polymorphic_cast</code> is preferred. </p> @@ -88,7 +90,18 @@ 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> and <code>polymorphic_cast</code> work with built-in pointer types only, + <code>polymorphic_pointer_downcast</code> and <code>polymorphic_pointer_cast</code> are more generic versions + with support for any pointer type for which the following expressions would be valid:<br><br> + + <p> For <code>polymorphic_pointer_downcast</code>:</p> + <code> static_pointer_cast<Derived>(p);<br> dynamic_pointer_cast<Derived>(p);</code><br><br> + + <p> For <code>polymorphic_pointer_cast</code>:</p> + <code> dynamic_pointer_cast<Derived>(p);<br> !p; // conversion to bool with negation</code><br><br> + <p>This includes C++ built-in pointers, <code>std::shared_ptr, boost::shared_ptr, boost::intrusive_ptr</code>, etc.</p> + + <h3>polymorphic_cast, polymorphic_downcast, polymorphic_pointer_cast and polymorphic_pointer_downcast synopsis</h3> <blockquote> <pre>namespace boost { @@ -103,6 +116,16 @@ 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_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 ); +// Returns: static_pointer_cast<Derived>(x) + } </pre> </blockquote> @@ -122,14 +145,41 @@ void f( Fruit * fruit ) { </pre> </blockquote> + <h3>polymorphic_pointer_downcast example</h3> + + <blockquote> +<pre>#include <boost/polymorphic_pointer_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> and + <code>polymorphic_pointer_cast</code> by Antony Polukhin.<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> diff --git a/libs/conversion/index.html b/libs/conversion/index.html index fbfe63a5b..afc39d3f7 100644 --- a/libs/conversion/index.html +++ b/libs/conversion/index.html @@ -27,10 +27,14 @@ 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/polymorphic_cast.hpp and boost/polymorphic_pointer_cast.hpp</a> + headers provide <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 boost/implicit_cast.hpp header provides <b>implicit_cast<></b> + to perform implicit casts only (no down-cast, no void*->T*, no U->T if T has only explicit constructors for U).<br> + </li> <li>The <a href="../../doc/html/boost_lexical_cast.html">boost/lexical_cast</a> header provides <b>lexical_cast<></b> general literal text conversions, such as an <code>int</code> represented as a <code>string</code>, or vice-versa.</li> diff --git a/libs/conversion/test/implicit_cast.cpp b/libs/conversion/test/implicit_cast.cpp index 0cad067cf..eaca42a83 100644 --- a/libs/conversion/test/implicit_cast.cpp +++ b/libs/conversion/test/implicit_cast.cpp @@ -29,7 +29,7 @@ int main() type<foo> f = check_return(boost::implicit_cast<foo>("hello")); type<long> z = check_return(boost::implicit_cast<long>(foo("hello"))); - // warning supression: + // warning suppression: (void)x; (void)f; (void)z; diff --git a/libs/conversion/test/polymorphic_cast_test.cpp b/libs/conversion/test/polymorphic_cast_test.cpp index b3f139768..db448503f 100644 --- a/libs/conversion/test/polymorphic_cast_test.cpp +++ b/libs/conversion/test/polymorphic_cast_test.cpp @@ -1,9 +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, Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. // @@ -12,8 +14,13 @@ #define BOOST_ENABLE_ASSERT_HANDLER #include <boost/polymorphic_cast.hpp> +#include <boost/polymorphic_pointer_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 +44,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"; } @@ -97,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<Derived>( 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<Derived>( base ) threw std::bad_cast" ); + } + + Base2 * base2; + + try + { + base2 = boost::polymorphic_pointer_cast<Base2>( 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<Base2>( base ) threw std::bad_cast" ); + } + + boost::shared_ptr<Base> sp_base( base ); + boost::shared_ptr<Base2> sp_base2; + try + { + sp_base2 = boost::polymorphic_pointer_cast<Base2>( 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<Base2>( 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; @@ -115,6 +183,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; @@ -124,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<Derived>( base ), std::bad_cast ); + delete base; + + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::shared_ptr<Base>(new Base) ), std::bad_cast ); + +#ifndef BOOST_NO_CXX11_SMART_PTR + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( std::shared_ptr<Base>(new Base) ), std::bad_cast ); +#endif + + BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::intrusive_ptr<Base>(new Base) ), std::bad_cast ); +} + static void test_polymorphic_downcast_fail() { Base * base = new Base; @@ -139,12 +286,83 @@ 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_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(); + 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(); } |