Use boost::addressof and update docs

This commit is contained in:
Antony Polukhin
2020-01-25 10:59:32 +03:00
parent e130cd860c
commit 58c33270a2
3 changed files with 106 additions and 81 deletions

View File

@ -1,5 +1,7 @@
[/ [/
Copyright 2016 Mikhail Maximov. Copyright 2016 Mikhail Maximov.
Copyright 2020 Antony Polukhin.
Distributed under the Boost Software License, Version 1.0. (See accompanying Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>) file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)
] ]
@ -8,15 +10,15 @@
[quickbook 1.6] [quickbook 1.6]
[compatibility-mode 1.5] [compatibility-mode 1.5]
[id conversion] [id conversion]
[version 1.6] [version 1.7]
[authors [Stroustrup, Bjarne], [Abrahams, Dave], [Rasin, Boris], [Polukhin, Antony]] [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 [license
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
[@http://www.boost.org/LICENSE_1_0.txt]) [@http://www.boost.org/LICENSE_1_0.txt])
] ]
[source-mode teletype] [source-mode c++]
] ]
[/ QuickBook Document version 1.5 ] [/ 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. 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] [endsect]
[section Polymorphic casts] [section Polymorphic casts]
Pointers to polymorphic objects (objects of classes which define at Pointers to polymorphic objects (objects of classes which define at
least one virtual function) are sometimes downcast or crosscast. 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. tools.
[#polymorphic_downcast] [#polymorphic_downcast]
[section polymorphic_downcast]
The C++ built-in `static_cast` can be used for efficiently The C++ built-in `static_cast` can be used for efficiently
downcasting pointers to polymorphic objects, but provides no error 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. succeeds.
A `polymorphic_downcast` should be used for 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 only performed in translation units where `NDEBUG` is
not defined, via not defined, via
``` ```
assert( dynamic_cast<Derived>(x) == x ) assert( dynamic_cast<Derived>(x) == x )
``` ```
where `x` is the source pointer. This approach where `x` is the source pointer. This approach
ensures that not only is a non-zero pointer returned, but also 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. fail to compile.
[warning Because `polymorphic_downcast` uses `assert()`, it [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] defined across translation units. See ISO Std 3.2]
[h4 Example:]
```
#include <boost/polymorphic_cast.hpp>
...
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<Banana*>(fruit);
...
}
```
[endsect]
[#polymorphic_cast] [#polymorphic_cast]
[section polymorphic_cast]
The C++ built-in `dynamic_cast` can be used for downcasts and The C++ built-in `dynamic_cast` can be used for downcasts and
crosscasts of pointers to polymorphic objects, but error notification in 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. 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. 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] [#polymorphic_pointer_cast]
[section polymorphic_pointer_cast]
While `polymorphic_downcast` and `polymorphic_cast` work with built-in pointer types only, While `polymorphic_downcast` and `polymorphic_cast` work with built-in pointer types only,
`polymorphic_pointer_downcast` and `polymorphic_pointer_cast` are more generic versions `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: with support for any pointer type for which the following expressions would be valid:
For `polymorphic_pointer_downcast`: For `polymorphic_pointer_downcast`:
``` ```
static_pointer_cast<Derived>(p); static_pointer_cast<Derived>(p);
dynamic_pointer_cast<Derived>(p); dynamic_pointer_cast<Derived>(p);
``` ```
For `polymorphic_pointer_cast`: For `polymorphic_pointer_cast`:
``` ```
dynamic_pointer_cast<Derived>(p); dynamic_pointer_cast<Derived>(p);
!p; // conversion to bool with negation !p; // conversion to bool with negation
``` ```
This includes C++ built-in pointers, `std::shared_ptr`, This includes C++ built-in pointers, `std::shared_ptr`,
`boost::shared_ptr`, `boost::intrusive_ptr`, etc. `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 <boost/polymorphic_pointer_cast.hpp>
template <class Derived, class Base> class Fruit { public: virtual ~Fruit(){} };
inline Derived polymorphic_cast(Base* x); class Banana : public Fruit {};
// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
// Returns: dynamic_cast<Derived>(x)
template <class Derived, class Base> // Use one of these:
inline Derived polymorphic_downcast(Base* x); typedef Fruit* FruitPtr;
// Effects: assert( dynamic_cast<Derived>(x) == x ); typedef std::shared_ptr<Fruit> FruitPtr;
// Returns: static_cast<Derived>(x) typedef boost::shared_ptr<Fruit> FruitPtr;
typedef boost::intrusive_ptr<Fruit> FruitPtr;
template <class Derived, class Base> void f(FruitPtr fruit) {
inline auto polymorphic_pointer_cast(Base x); // ... logic which leads us to believe it is a banana
// Throws: std::bad_cast if ( dynamic_pointer_cast<Derived>(x) == 0 ) auto banana = boost::polymorphic_pointer_downcast<Banana>(fruit);
// Returns: dynamic_pointer_cast<Derived>(x) ...
}
```
template <class Derived, class Base> [endsect]
inline auto polymorphic_pointer_downcast(Base x);
// Effects: assert( dynamic_pointer_cast<Derived>(x) == x );
// Returns: static_pointer_cast<Derived>(x)
} [endsect]
[section Synopsis]
```
namespace boost {
// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
// Returns: dynamic_cast<Derived>(x)
template <class Derived, class Base>
inline Derived polymorphic_cast(Base* x);
// Effects: assert( dynamic_cast<Derived>(x) == x );
// Returns: static_cast<Derived>(x)
template <class Derived, class Base>
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_downcast(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_cast(Base x);
// Effects: assert( dynamic_pointer_cast<Derived>(x) == x );
// Returns: static_pointer_cast<Derived>(x)
template <class Derived, class Base>
inline auto polymorphic_pointer_downcast(Base x);
}
``` ```
[endsect] [endsect]
[section `polymorphic_downcast` example]
```
#include <boost/polymorphic_cast.hpp>
...
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<Banana*>(fruit);
...
}
```
[endsect]
[section `polymorphic_pointer_downcast` example]
```
#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);
...
}
```
[endsect]
[section History] [section History]
`polymorphic_cast` was suggested by Bjarne Stroustrup in "The C++ Programming Language". `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] `polymorphic_pointer_downcast` was contributed by [@http://www.boost.org/people/boris_rasin.htm Boris Rasin]
and `polymorphic_pointer_cast` by Antony Polukhin. 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] 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] [endsect]

View File

@ -2,8 +2,9 @@
// Distributed under the Boost Software License, Version 1.0. (See // Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at // accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // 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 { namespace boost {
@ -26,11 +27,7 @@ inline T implicit_cast (typename boost::detail::icast_identity<T>::type x) {
return x; return x;
} }
// incomplete return type now is here
//template <typename T>
//void implicit_cast (...);
} // namespace boost } // namespace boost
#endif // IMPLICIT_CAST_DWA200356_HPP #endif // BOOST_IMPLICIT_CAST_DWA200356_HPP

View File

@ -50,17 +50,20 @@
#define BOOST_POLYMORPHIC_CAST_HPP #define BOOST_POLYMORPHIC_CAST_HPP
# include <boost/config.hpp> # 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 #ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once # pragma once
#endif #endif
# include <boost/assert.hpp>
# include <boost/core/addressof.hpp>
# include <boost/core/enable_if.hpp>
# include <boost/throw_exception.hpp>
# include <boost/type_traits/is_reference.hpp>
# include <boost/type_traits/remove_reference.hpp>
# include <typeinfo>
namespace boost namespace boost
{ {
// See the documentation for descriptions of how to choose between // See the documentation for descriptions of how to choose between
@ -108,10 +111,14 @@ namespace boost
// Contributed by Julien Delacroix // Contributed by Julien Delacroix
template <class Target, class Source> template <class Target, class Source>
inline typename boost::enable_if_c<boost::is_reference<Target>::value, Target>::type polymorphic_downcast(Source &x) 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); typedef typename boost::remove_reference<Target>::type* target_pointer_type;
return static_cast<Target>(x); return *boost::polymorphic_downcast<target_pointer_type>(
boost::addressof(x)
);
} }
} // namespace boost } // namespace boost