1 // 2 // cpp11_pointer_cast_test.cpp - a test for boost/pointer_cast.hpp with std::shared_ptr and std::unique_ptr 3 // 4 // Copyright (c) 2016 Karolin Varner 5 // 6 // Distributed under the Boost Software License, Version 1.0. (See 7 // accompanying file LICENSE_1_0.txt or copy at 8 // http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #include <boost/pointer_cast.hpp> 12 13 #include <boost/config.hpp> 14 #include <boost/core/lightweight_test.hpp> 15 #include <boost/get_pointer.hpp> 16 #include <boost/shared_ptr.hpp> 17 18 #include <memory> 19 #include <utility> 20 #include <functional> 21 22 #if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) \ 23 || defined( BOOST_NO_CXX11_HDR_FUNCTIONAL ) \ 24 || defined( BOOST_NO_CXX11_HDR_UTILITY ) \ 25 || defined( BOOST_NO_CXX11_LAMBDAS ) \ 26 || defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) 27 28 // We expect all the features or none of the features to be 29 // available, since we should be on C++11 main()30int main() { return 0; } 31 32 #else 33 34 namespace 35 { 36 37 // Let's create these inheritance relationship: 38 // 39 // base base2 40 // | | 41 // derived 42 // | 43 // derived_derived 44 // 45 46 class base 47 { 48 public: ~base()49 virtual ~base(){} 50 int filler [5]; 51 }; 52 53 class base2 54 { 55 public: 56 ~base2()57 virtual ~base2(){} 58 int filler [5]; 59 }; 60 61 class derived 62 : public base, public base2 63 { 64 int filler [5]; 65 }; 66 67 class derived_derived 68 : public derived 69 { 70 int filler [5]; 71 }; 72 73 // And now some simple check functions 74 75 #if !defined( BOOST_NO_RTTI ) 76 77 template <class BasePtr> check_dynamic_pointer_cast(const BasePtr & ptr)78bool check_dynamic_pointer_cast(const BasePtr &ptr) 79 { 80 //Check that dynamic_pointer_cast versus dynamic_cast 81 return 82 //Correct cast with dynamic_pointer_cast 83 boost::get_pointer(boost::dynamic_pointer_cast<derived>(ptr)) == 84 //Correct cast with dynamic_cast 85 dynamic_cast<derived*>(boost::get_pointer(ptr)) 86 && 87 //Incorrect cast with dynamic_pointer_cast 88 boost::get_pointer(boost::dynamic_pointer_cast<derived_derived>(ptr)) == 89 //Incorrect cast with dynamic_cast 90 dynamic_cast<derived_derived*>(boost::get_pointer(ptr)); 91 } 92 93 #endif 94 95 template <class BasePtr> check_static_pointer_cast(const BasePtr & ptr)96bool check_static_pointer_cast(const BasePtr &ptr) 97 { 98 return 99 //Cast base -> derived -> base2 using static_pointer_cast 100 boost::get_pointer( 101 boost::static_pointer_cast<base2>( 102 boost::static_pointer_cast<derived>(ptr))) == 103 //Now the same with static_cast 104 static_cast<base2*>(static_cast<derived*>(boost::get_pointer(ptr))); 105 } 106 107 template <class BasePtr> check_const_pointer_cast(const BasePtr & ptr)108bool check_const_pointer_cast(const BasePtr &ptr) 109 { 110 return 111 //Unconst and const again using const_pointer_cast 112 boost::get_pointer( 113 boost::const_pointer_cast<const base> 114 (boost::const_pointer_cast<base>(ptr))) == 115 //Now the same with const_cast 116 const_cast<const base*>(const_cast<base*>(boost::get_pointer(ptr))); 117 } 118 119 template <class BasePtr> check_all_copy_casts(const BasePtr & ptr)120void check_all_copy_casts(const BasePtr &ptr) 121 { 122 #if !defined( BOOST_NO_RTTI ) 123 BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); 124 #endif 125 BOOST_TEST( check_static_pointer_cast( ptr ) ); 126 BOOST_TEST( check_const_pointer_cast( ptr ) ); 127 } 128 129 130 #if !defined( BOOST_NO_RTTI ) 131 132 template <class BasePtr> check_dynamic_moving_pointer_cast(std::function<BasePtr ()> f)133bool check_dynamic_moving_pointer_cast(std::function<BasePtr()> f) 134 { 135 BasePtr smart1 = f(), smart2 = f(); 136 derived* expect1 = dynamic_cast<derived*>(boost::get_pointer(smart1)); 137 derived_derived* expect2 = dynamic_cast<derived_derived*>(boost::get_pointer(smart2)); 138 //Check that dynamic_pointer_cast versus dynamic_cast 139 return 140 //Correct cast with dynamic_pointer_cast 141 boost::get_pointer(boost::dynamic_pointer_cast<derived>( std::move(smart1) )) == expect1 142 && 143 //Incorrect cast with dynamic_pointer_cast 144 boost::get_pointer(boost::dynamic_pointer_cast<derived_derived>( std::move(smart2) )) == expect2; 145 } 146 147 #endif 148 149 template <class BasePtr> check_static_moving_pointer_cast(std::function<BasePtr ()> f)150bool check_static_moving_pointer_cast(std::function<BasePtr()> f) 151 { 152 BasePtr smart = f(); 153 base2 *expect = static_cast<base2*>(static_cast<derived*>(boost::get_pointer(smart))); 154 155 return 156 //Cast base -> derived -> base2 using static_pointer_cast 157 boost::get_pointer( 158 boost::static_pointer_cast<base2>( 159 boost::static_pointer_cast<derived>( std::move(smart) ))) == 160 //Now the same with static_cast 161 expect; 162 } 163 164 template <class BasePtr> check_const_moving_pointer_cast(std::function<BasePtr ()> f)165bool check_const_moving_pointer_cast(std::function<BasePtr()> f) 166 { 167 BasePtr smart = f(); 168 const base *expect = const_cast<const base*>(const_cast<base*>(boost::get_pointer(smart))); 169 return 170 //Unconst and const again using const_pointer_cast 171 boost::get_pointer( 172 boost::const_pointer_cast<const base> 173 (boost::const_pointer_cast<base>( std::move(smart) ))) == 174 //Now the same with const_cast 175 expect; 176 } 177 178 template <class BasePtr> check_all_moving_casts(std::function<BasePtr ()> f)179void check_all_moving_casts(std::function<BasePtr()> f) { 180 #if !defined( BOOST_NO_RTTI ) 181 BOOST_TEST( check_dynamic_moving_pointer_cast( f ) ); 182 #endif 183 BOOST_TEST( check_static_moving_pointer_cast( f ) ); 184 BOOST_TEST( check_const_moving_pointer_cast( f ) ); 185 } 186 187 } 188 main()189int main() 190 { 191 192 std::shared_ptr<base> std_shared(new derived); 193 boost::shared_ptr<base> boost_shared(new derived); 194 base *plain = boost_shared.get(); 195 196 // plain & boost::shared_ptr moving pointer_cast checks; there 197 // is no specific handleing for those types at the moment; this 198 // test just makes sure they won't break when std::move() is used 199 // in generic code 200 201 check_all_moving_casts<boost::shared_ptr<base>>([&boost_shared]() { 202 return boost_shared; 203 }); 204 205 check_all_moving_casts<base*>([plain]() { 206 return plain; 207 }); 208 209 // std::shared_ptr casts 210 211 check_all_copy_casts(std_shared); 212 check_all_moving_casts<std::shared_ptr<base>>([&std_shared]() { 213 return std_shared; 214 }); 215 216 // std::unique_ptr casts 217 218 check_all_moving_casts<std::unique_ptr<base>>([]() { 219 return std::unique_ptr<base>(new derived); 220 }); 221 222 return boost::report_errors(); 223 } 224 #endif 225