// (by Ariel Badichi) #include <cassert>
#include <boost/type_traits/remove_reference.hpp>
class A { public: virtual ~A() {} };
class B : public A { };
template<typename Target, typename Source> Target polymorphic_downcast(Source *x) { assert(dynamic_cast<Target>(x) == x); return static_cast<Target>(x); }
template<typename Target, typename Source> Target polymorphic_downcast(Source & x) { typedef typename boost::remove_reference<Target>::type noref; assert(dynamic_cast<noref *>(&x) == &x); return static_cast<Target>(x); }
int main() { A a; B b;
A *aptr = &b; B *bptr = polymorphic_downcast<B *>(aptr);
// should assert /* aptr = &a; bptr = polymorphic_downcast<B *>(aptr); */
A & aref = b; B & bref = polymorphic_downcast<B &>(aref);
// should assert (not throw an exception) /* A & aref2 = a; B & bref2 = polymorphic_downcast<B &>(aref2); */
return 0; }
// the compilter will complain:
2.2.cpp: In function `int main()':
2.2.cpp:62: error: call of overloaded `polymorphic_downcast(A*&)' is ambiguous
2.2.cpp:43: note: candidates are: Target polymorphic_downcast(Source*) [with Target = B*, Source = A]
2.2.cpp:50: note: Target polymorphic_downcast(Source&) [with Target = B*, Source = A*]
#include "boost/cast.hpp" #include "boost/type_traits.hpp"
using boost::polymorphic_downcast;
template <typename Derived, typename Base> Derived polymorphic_downcast(Base& base) { return *polymorphic_downcast<boost::remove_reference<Derived>::type*>(&base); }
namespace { class B{ public: virtual void fn() {} }; class D: public B {};
void fn() { D d;
// Our version B& br = d; D& dr = polymorphic_downcast<D&>(br);
// Boost's version B* bp = &d; D* dp = polymorphic_downcast<D*>(bp); } }
This last solution seems not to compile on my g++ system...
ex2_alt.cpp: In function `void <unnamed>::fn()': ex2_alt.cpp:27: call of overloaded `polymorphic_downcast(<unnamed>::B*&)' is ambiguous ../boost/boost/cast.hpp:96: candidates are:
Target boost::polymorphic_downcast(Source*) [with Target = <unnamed>::D*, Source = <unnamed>::B]ex2_alt.cpp:8:
Derived polymorphic_downcast(Base&) [with Derived = <unnamed>::D*, Base = <unnamed>::B*]
(the unnamed is just the anonymous namespace...)
My solution, although probably too complex (could someone please comment on this (daboe1 -/- gmail.com): (also the boost::is_reference<T>::value does not seem to work if T gets replaced by S)
#include <boost/type_traits.hpp> #include <cassert>
template <class T, class S, bool is_ref> struct polymorphic_downcast_impl { static inline T do_it( S s ) { assert( dynamic_cast<T>( s ) == s ); return static_cast<T>( s ); } };
template <class T, class S> struct polymorphic_downcast_impl<T,S,true> { typedef typename boost::remove_reference<T>::type noref; static inline T do_it( S s ) { assert( dynamic_cast<noref*>( &s ) == &s ); return static_cast<T>( s ); } };
template <class T, class S> T polymorphic_downcast( S s ) { static const bool is_ref = boost::is_reference<T>::value; return polymorphic_downcast_impl<T,S,is_ref>::do_it( s ); }
struct A { virtual ~A() {} }; struct B : A {};
int main( void ) { B b; A* a_ptr = &b; B* b_ptr = polymorphic_downcast<B*>( a_ptr );
A& a_ref = b; B& b_ref = polymorphic_downcast<B&>( a_ref );
return 0; }