From 58c33270a2761d51d40a8b94912afa96c6b8617e Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 25 Jan 2020 10:59:32 +0300 Subject: [PATCH] Use boost::addressof and update docs --- doc/conversion.qbk | 151 ++++++++++++++++------------- include/boost/implicit_cast.hpp | 11 +-- include/boost/polymorphic_cast.hpp | 25 +++-- 3 files changed, 106 insertions(+), 81 deletions(-) diff --git a/doc/conversion.qbk b/doc/conversion.qbk index bbcd3d0..8cc2344 100644 --- a/doc/conversion.qbk +++ b/doc/conversion.qbk @@ -1,5 +1,7 @@ [/ Copyright 2016 Mikhail Maximov. + Copyright 2020 Antony Polukhin. + 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,15 +10,15 @@ [quickbook 1.6] [compatibility-mode 1.5] [id conversion] - [version 1.6] + [version 1.7] [authors [Stroustrup, Bjarne], [Abrahams, Dave], [Rasin, Boris], [Polukhin, Antony]] - [copyright 2001 Beman Dawes, 2014-2019 Antony Polukhin] + [copyright 2001 Beman Dawes, 2014-2020 Antony Polukhin] [license 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]) ] - [source-mode teletype] + [source-mode c++] ] [/ QuickBook Document version 1.5 ] @@ -44,7 +46,7 @@ the Boost Conversion Library is supplied by several headers: provides [@boost:libs/lexical_cast/doc/html/index.html `lexical_cast<>`] general literal text conversions, such as an `int` represented as a `string`, or vice-versa. [endsect] - + [section Polymorphic casts] Pointers to polymorphic objects (objects of classes which define at least one virtual function) are sometimes downcast or crosscast. @@ -58,6 +60,7 @@ safety, suffer poor readability, and are difficult to locate with search tools. [#polymorphic_downcast] +[section polymorphic_downcast] The C++ built-in `static_cast` can be used for efficiently downcasting pointers to polymorphic objects, but provides no error @@ -68,11 +71,11 @@ debug compilations adds safety via an `assert()` that a `dynamic_cast` succeeds. A `polymorphic_downcast` should be used for -downcasts that you are certain should succeed. Error checking is +downcasts that you are certain should succeed. Error checking is only performed in translation units where `NDEBUG` is not defined, via ``` - assert( dynamic_cast(x) == x ) + assert( dynamic_cast(x) == x ) ``` where `x` is the source pointer. This approach ensures that not only is a non-zero pointer returned, but also @@ -81,10 +84,26 @@ Attempts to crosscast using `polymorphic_downcast` will fail to compile. [warning Because `polymorphic_downcast` uses `assert()`, it -violates the One Definition Rule (ODR) if NDEBUG is inconsistently +violates the One Definition Rule (ODR) if `NDEBUG` is inconsistently defined across translation units. See ISO Std 3.2] +[h4 Example:] +``` + #include + ... + class Fruit { public: virtual ~Fruit(){}; ... }; + class Banana : public Fruit { ... }; + ... + void f( Fruit * fruit ) { + // ... logic which leads us to believe it is a Banana + Banana * banana = boost::polymorphic_downcast(fruit); + ... + } +``` +[endsect] + [#polymorphic_cast] +[section polymorphic_cast] The C++ built-in `dynamic_cast` can be used for downcasts and crosscasts of pointers to polymorphic objects, but error notification in @@ -102,88 +121,88 @@ or when efficiency is not important, `polymorphic_cast` is preferred. The C++ built-in `dynamic_cast` must be used to cast references rather than pointers. It is also the only cast that can be used to check whether a given interface is supported; in that case a return of 0 isn't an error condition. +[endsect] + + [#polymorphic_pointer_cast] +[section polymorphic_pointer_cast] 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: For `polymorphic_pointer_downcast`: ``` - static_pointer_cast(p); - dynamic_pointer_cast(p); + static_pointer_cast(p); + dynamic_pointer_cast(p); ``` For `polymorphic_pointer_cast`: ``` - dynamic_pointer_cast(p); - !p; // conversion to bool with negation + dynamic_pointer_cast(p); + !p; // conversion to bool with negation ``` This includes C++ built-in pointers, `std::shared_ptr`, `boost::shared_ptr`, `boost::intrusive_ptr`, etc. -[endsect] -[section `polymorphic_cast`, `polymorphic_downcast`, `polymorphic_pointer_cast` and `polymorphic_pointer_downcast` synopsis] + +[h4 Example:] ``` - namespace boost { + #include - template - inline Derived polymorphic_cast(Base* x); - // Throws: std::bad_cast if ( dynamic_cast(x) == 0 ) - // Returns: dynamic_cast(x) + class Fruit { public: virtual ~Fruit(){} }; + class Banana : public Fruit {}; - template - inline Derived polymorphic_downcast(Base* x); - // Effects: assert( dynamic_cast(x) == x ); - // Returns: static_cast(x) + // Use one of these: + typedef Fruit* FruitPtr; + typedef std::shared_ptr FruitPtr; + typedef boost::shared_ptr FruitPtr; + typedef boost::intrusive_ptr FruitPtr; - template - inline auto polymorphic_pointer_cast(Base x); - // Throws: std::bad_cast if ( dynamic_pointer_cast(x) == 0 ) - // Returns: dynamic_pointer_cast(x) + void f(FruitPtr fruit) { + // ... logic which leads us to believe it is a banana + auto banana = boost::polymorphic_pointer_downcast(fruit); + ... + } +``` - template - inline auto polymorphic_pointer_downcast(Base x); - // Effects: assert( dynamic_pointer_cast(x) == x ); - // Returns: static_pointer_cast(x) +[endsect] - } +[endsect] + +[section Synopsis] +``` + namespace boost { + + // Throws: std::bad_cast if ( dynamic_cast(x) == 0 ) + // Returns: dynamic_cast(x) + template + inline Derived polymorphic_cast(Base* x); + + // Effects: assert( dynamic_cast(x) == x ); + // Returns: static_cast(x) + template + inline Derived polymorphic_downcast(Base* x); + + // Effects: assert( dynamic_cast(&x) == &x ); + // Returns: static_cast(x) + template + inline Derived polymorphic_downcast(Base& x); + + // Throws: std::bad_cast if ( dynamic_pointer_cast(x) == 0 ) + // Returns: dynamic_pointer_cast(x) + template + inline auto polymorphic_pointer_cast(Base x); + + // Effects: assert( dynamic_pointer_cast(x) == x ); + // Returns: static_pointer_cast(x) + template + inline auto polymorphic_pointer_downcast(Base x); + + } ``` [endsect] -[section `polymorphic_downcast` example] -``` - #include - ... - class Fruit { public: virtual ~Fruit(){}; ... }; - class Banana : public Fruit { ... }; - ... - void f( Fruit * fruit ) { - // ... logic which leads us to believe it is a Banana - Banana * banana = boost::polymorphic_downcast(fruit); - ... - } -``` -[endsect] -[section `polymorphic_pointer_downcast` example] -``` - #include - class Fruit { public: virtual ~Fruit(){} }; - class Banana : public Fruit {}; - // use one of these: - - typedef Fruit* FruitPtr; - typedef std::shared_ptr FruitPtr; - typedef boost::shared_ptr FruitPtr; - typedef boost::intrusive_ptr FruitPtr; - - void f(FruitPtr fruit) { - // ... logic which leads us to believe it is a banana - auto banana = boost::polymorphic_pointer_downcast(fruit); - ... - } -``` -[endsect] [section History] `polymorphic_cast` was suggested by Bjarne Stroustrup in "The C++ Programming Language". @@ -192,6 +211,8 @@ This includes C++ built-in pointers, `std::shared_ptr`, `polymorphic_pointer_downcast` was contributed by [@http://www.boost.org/people/boris_rasin.htm Boris Rasin] and `polymorphic_pointer_cast` by Antony Polukhin. +`polymorphic_downcast` overload for references was contributed by Julien Delacroix. + An old `numeric_cast` that was contributed by [@http://www.boost.org/people/kevlin_henney.htm Kevlin Henney] -is now superseeded by the [@boost:numeric_conversion/doc/html/html/boost_numericconversion/improved_numeric_cast__.html Boost Numeric Conversion Library] +is now superseded by the [@boost:numeric_conversion/doc/html/html/boost_numericconversion/improved_numeric_cast__.html Boost Numeric Conversion Library] [endsect] diff --git a/include/boost/implicit_cast.hpp b/include/boost/implicit_cast.hpp index d82db76..03abe1d 100644 --- a/include/boost/implicit_cast.hpp +++ b/include/boost/implicit_cast.hpp @@ -2,8 +2,9 @@ // 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) -#ifndef IMPLICIT_CAST_DWA200356_HPP -# define IMPLICIT_CAST_DWA200356_HPP + +#ifndef BOOST_IMPLICIT_CAST_DWA200356_HPP +#define BOOST_IMPLICIT_CAST_DWA200356_HPP namespace boost { @@ -26,11 +27,7 @@ inline T implicit_cast (typename boost::detail::icast_identity::type x) { return x; } -// incomplete return type now is here -//template -//void implicit_cast (...); - } // namespace boost -#endif // IMPLICIT_CAST_DWA200356_HPP +#endif // BOOST_IMPLICIT_CAST_DWA200356_HPP diff --git a/include/boost/polymorphic_cast.hpp b/include/boost/polymorphic_cast.hpp index 802ac9a..3592506 100644 --- a/include/boost/polymorphic_cast.hpp +++ b/include/boost/polymorphic_cast.hpp @@ -50,17 +50,20 @@ #define BOOST_POLYMORPHIC_CAST_HPP # include -# include -# include -# include -# include -# include -# include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +# include +# include +# include +# include +# include +# include + +# include + namespace boost { // See the documentation for descriptions of how to choose between @@ -108,10 +111,14 @@ namespace boost // Contributed by Julien Delacroix template - inline typename boost::enable_if_c::value, Target>::type polymorphic_downcast(Source &x) + inline typename boost::enable_if_c< + boost::is_reference::value, Target + >::type polymorphic_downcast(Source& x) { - BOOST_ASSERT(dynamic_cast::type *>(&x) == &x); - return static_cast(x); + typedef typename boost::remove_reference::type* target_pointer_type; + return *boost::polymorphic_downcast( + boost::addressof(x) + ); } } // namespace boost