1[/ 2 Copyright 2016 Mikhail Maximov. 3 Copyright 2020 Antony Polukhin. 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 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>) 7] 8 9[article The Conversion Library 10 [quickbook 1.6] 11 [compatibility-mode 1.5] 12 [id conversion] 13 [version 1.7] 14 [authors [Stroustrup, Bjarne], [Abrahams, Dave], [Rasin, Boris], [Polukhin, Antony]] 15 [copyright 2001 Beman Dawes, 2014-2020 Antony Polukhin] 16 [license 17 Distributed under the Boost Software License, Version 1.0. 18 (See accompanying file LICENSE_1_0.txt or copy at 19 [@http://www.boost.org/LICENSE_1_0.txt]) 20 ] 21 [source-mode c++] 22] 23 24[/ QuickBook Document version 1.5 ] 25[/ Dec, 2016 ] 26 27[section Description] 28 29The Conversion Library improves program safety and clarity by performing 30otherwise messy conversions. It includes cast-style function templates designed 31to complement the C++ Standard's built-in casts. 32 33To reduce coupling, particularly to standard library IOStreams, 34the Boost Conversion Library is supplied by several headers: 35 36# The [@boost:boost/polymorphic_cast.hpp boost/polymorphic_cast.hpp] header 37 provides [link polymorphic_cast `polymorphic_cast<>`] and 38 [link polymorphic_downcast `polymorphic_downcast<>`] 39 to perform safe casting between polymorphic types. 40# The [@boost:boost/polymorphic_pointer_cast.hpp boost/polymorphic_pointer_cast.hpp] header 41 provides [link polymorphic_pointer_cast `polymorphic_pointer_cast<>`] and 42 [link polymorphic_pointer_cast `polymorphic_pointer_downcast<>`] 43# The [@boost:boost/implicit_cast.hpp boost/implicit_cast.hpp] header provides `implicit_cast<>` 44 to perform implicit casts only (no down-cast, no void*->T*, no U->T if T has only explicit constructors for U). 45# The [@boost:boost/lexical_cast.hpp boost/lexical_cast.hpp] header 46 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. 47 48[endsect] 49 50[section Polymorphic casts] 51Pointers to polymorphic objects (objects of classes which define at 52least one virtual function) are sometimes downcast or crosscast. 53Downcasting means casting from a base class to a derived class. 54Crosscasting means casting across an inheritance hierarchy diagram, such 55as from one base to the other in a [^Y] diagram hierarchy. 56 57Such casts can be done with old-style casts, but this approach is 58never to be recommended. Old-style casts are sorely lacking in type 59safety, suffer poor readability, and are difficult to locate with search 60tools. 61 62[#polymorphic_downcast] 63[section polymorphic_downcast] 64 65The C++ built-in `static_cast` can be used for efficiently 66downcasting pointers to polymorphic objects, but provides no error 67detection for the case where the pointer being cast actually points to 68the wrong derived class. The `polymorphic_downcast` template retains 69the efficiency of `static_cast` for non-debug compilations, but for 70debug compilations adds safety via an `assert()` that a `dynamic_cast` 71succeeds. 72 73A `polymorphic_downcast` should be used for 74downcasts that you are certain should succeed. Error checking is 75only performed in translation units where `NDEBUG` is 76not defined, via 77``` 78 assert( dynamic_cast<Derived>(x) == x ) 79``` 80where `x` is the source pointer. This approach 81ensures that not only is a non-zero pointer returned, but also 82that it is correct in the presence of multiple inheritance. 83Attempts to crosscast using `polymorphic_downcast` will 84fail to compile. 85 86[warning Because `polymorphic_downcast` uses `assert()`, it 87violates the One Definition Rule (ODR) if `NDEBUG` is inconsistently 88defined across translation units. See ISO Std 3.2] 89 90[h4 Example:] 91``` 92 #include <boost/polymorphic_cast.hpp> 93 ... 94 class Fruit { public: virtual ~Fruit(){}; ... }; 95 class Banana : public Fruit { ... }; 96 ... 97 void f( Fruit * fruit ) { 98 // ... logic which leads us to believe it is a Banana 99 Banana * banana = boost::polymorphic_downcast<Banana*>(fruit); 100 ... 101 } 102``` 103[endsect] 104 105[#polymorphic_cast] 106[section polymorphic_cast] 107 108The C++ built-in `dynamic_cast` can be used for downcasts and 109crosscasts of pointers to polymorphic objects, but error notification in 110the form of a returned value of 0 is inconvenient to test, or worse yet, 111easy to forget to test. The throwing form of `dynamic_cast`, which 112works on references, can be used on pointers through the ugly expression 113`&dynamic_cast<T&>(*p)`, which causes undefined 114behavior if `p` is `0`. The `polymorphic_cast` 115template performs a `dynamic_cast` on a pointer, and throws an 116exception if the `dynamic_cast` returns 0. 117 118For crosscasts, or when the success of a cast can only be known at runtime, 119or when efficiency is not important, `polymorphic_cast` is preferred. 120 121The C++ built-in `dynamic_cast` must be used to cast references rather than pointers. 122It 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. 123 124[endsect] 125 126 127[#polymorphic_pointer_cast] 128[section polymorphic_pointer_cast] 129While `polymorphic_downcast` and `polymorphic_cast` work with built-in pointer types only, 130`polymorphic_pointer_downcast` and `polymorphic_pointer_cast` are more generic versions 131with support for any pointer type for which the following expressions would be valid: 132 133For `polymorphic_pointer_downcast`: 134``` 135 static_pointer_cast<Derived>(p); 136 dynamic_pointer_cast<Derived>(p); 137``` 138For `polymorphic_pointer_cast`: 139``` 140 dynamic_pointer_cast<Derived>(p); 141 !p; // conversion to bool with negation 142``` 143 144This includes C++ built-in pointers, `std::shared_ptr`, 145`boost::shared_ptr`, `boost::intrusive_ptr`, etc. 146 147 148[h4 Example:] 149``` 150 #include <boost/polymorphic_pointer_cast.hpp> 151 152 class Fruit { public: virtual ~Fruit(){} }; 153 class Banana : public Fruit {}; 154 155 // Use one of these: 156 typedef Fruit* FruitPtr; 157 typedef std::shared_ptr<Fruit> FruitPtr; 158 typedef boost::shared_ptr<Fruit> FruitPtr; 159 typedef boost::intrusive_ptr<Fruit> FruitPtr; 160 161 void f(FruitPtr fruit) { 162 // ... logic which leads us to believe it is a banana 163 auto banana = boost::polymorphic_pointer_downcast<Banana>(fruit); 164 ... 165 } 166``` 167 168[endsect] 169 170[endsect] 171 172[section Synopsis] 173``` 174 namespace boost { 175 176 // Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 ) 177 // Returns: dynamic_cast<Derived>(x) 178 template <class Derived, class Base> 179 inline Derived polymorphic_cast(Base* x); 180 181 // Effects: assert( dynamic_cast<Derived>(x) == x ); 182 // Returns: static_cast<Derived>(x) 183 template <class Derived, class Base> 184 inline Derived polymorphic_downcast(Base* x); 185 186 // Effects: assert( dynamic_cast<Derived>(&x) == &x ); 187 // Returns: static_cast<Derived>(x) 188 template <class Derived, class Base> 189 inline Derived polymorphic_downcast(Base& x); 190 191 // Throws: std::bad_cast if ( dynamic_pointer_cast<Derived>(x) == 0 ) 192 // Returns: dynamic_pointer_cast<Derived>(x) 193 template <class Derived, class Base> 194 inline auto polymorphic_pointer_cast(Base x); 195 196 // Effects: assert( dynamic_pointer_cast<Derived>(x) == x ); 197 // Returns: static_pointer_cast<Derived>(x) 198 template <class Derived, class Base> 199 inline auto polymorphic_pointer_downcast(Base x); 200 201 } 202``` 203[endsect] 204 205 206[section History] 207`polymorphic_cast` was suggested by Bjarne Stroustrup in "The C++ Programming Language". 208 209`polymorphic_downcast` was contributed by [@http://www.boost.org/people/dave_abrahams.htm Dave Abrahams]. 210 211`polymorphic_pointer_downcast` was contributed by [@http://www.boost.org/people/boris_rasin.htm Boris Rasin] 212and `polymorphic_pointer_cast` by Antony Polukhin. 213 214`polymorphic_downcast` overload for references was contributed by Julien Delacroix. 215 216An old `numeric_cast` that was contributed by [@http://www.boost.org/people/kevlin_henney.htm Kevlin Henney] 217is now superseded by the [@boost:numeric_conversion/doc/html/html/boost_numericconversion/improved_numeric_cast__.html Boost Numeric Conversion Library] 218[endsect] 219