Boost logo

Boost Users :

From: Scott Meyers (usenet_at_[hidden])
Date: 2006-03-10 14:41:30


It took me a little while to figure out that get<T> on a variant is really just
the moral equivalent of dynamic_cast<T> with a funny syntax. I'd like to
understand why, given a variant v, this syntax is used

   T* p = get<T>(&v);
   T& r = get<T>(v);

instead of this:

   T* p = variant_cast<T*>(&v);
   T& r = variant_cast<T&>(v);

any_cast on pointers also uses what I consider to be a counterintuitive syntax,
using this (for an any object a)

   T* p = any_cast<T>(&a)

instead of this:

   T* p = any_cast<T*>(&a)

However, any_cast to a reference works with a syntax analogous to dynamic_cast.

Implementing the "expected" syntax doesn't seem to be too difficult. For
example, here's my quick cut at variant_cast:

   template<typename T, typename U1, typename U2, typename U3>
   T variant_cast(boost::variant<U1, U2, U3>& v) // ref
   {
     using namespace boost;
     BOOST_STATIC_ASSERT(is_reference<T>::value);
     return get<remove_reference<T>::type>(v);
   }

   template<typename T, typename U1, typename U2, typename U3>
   T variant_cast(const boost::variant<U1, U2, U3>& v) //ref-to-const
   {
     using namespace boost;
     BOOST_STATIC_ASSERT(is_reference<T>::value);
     return get<remove_reference<T>::type>(v);
   }

   template<typename T, typename U1, typename U2, typename U3>
   T variant_cast(boost::variant<U1, U2, U3> *pv) // ptr
   {
     using namespace boost;
     BOOST_STATIC_ASSERT(is_pointer<T>::value);
     return get<remove_pointer<T>::type>(pv);
   }

   template<typename T, typename U1, typename U2, typename U3>
   T variant_cast(const boost::variant<U1, U2, U3> *pv) // ptr-to-const
   {
     using namespace boost;
     BOOST_STATIC_ASSERT(is_pointer<T>::value);
     return get<remove_pointer<T>::type>(pv);
   }

In a thread last month, Marc Mutz posted this approach to "normalizing" the
syntax of any_cast:

     template <typename T> class any_cast2 : noncopyable {
         const any & m_any;
     public:
         explicit any_cast2( const any & v ) : m_any( v ) {}
         operator T() const { return any_cast<T>( m_any ); }
     };

     template <typename T> class any_cast2<T*> : noncopyable {
         any * const m_any;
     public:
         explicit any_cast2( any * v ) : m_any( v ) {}
         operator T * () const { return any_cast<T>( m_any ); }
     };

     template <typename T> class any_cast2<const T*> : noncopyable {
         const any * const m_any;
     public:
         explicit any_cast2( const any * v ) : m_any( v ) {}
         operator const T * () const { return any_cast<T>( m_any ); }
     };

     template <typename T> class any_cast2<T&> : noncopyable {
         any & m_any;
     public:
         explicit any_cast2( any & v ) : m_any( v ) {}
         operator T & () const { return any_cast<T&>( m_any ); }
     };

     template <typename T> class any_cast2<const T&> : noncopyable {
         const any & m_any;
     public:
         explicit any_cast2( const any & v ) : m_any( v ) {}
         operator const T & () const { return any_cast<const T&>( m_any ); }
     };

Maybe there are problems to these approaches -- I've hardly investigated them.
But I would be interested to know if there is a good reason for the syntaxes for
dynamic_cast, any_cast, and get to vary so much.

Thanks,

Scott


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net