[Home]CPPTM Answers - Exercise 2-2

BOOST WIKI | RecentChanges | Preferences | Page List | Links List

 // (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*]

A solution

 #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);
     }
 }

Edit by Daboe_

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;
 }

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited August 29, 2007 3:36 am (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers