Listing 4: The final variant_t definition
#ifndef VARIANT_H #define VARIANT_H class variant_t { public : variant_t() : data ( NULL ) {} variant_t( const variant_t & rhs ) { if ( rhs.data != NULL ) rhs.data->AddRef() ; data = rhs.data ; } ~variant_t() { if ( data != NULL ) data->Release() ; } // NOTE: This code takes care of self-asignment. // DO NOT CHANGE THE ORDER of the statements. variant_t& operator = ( const variant_t& rhs ) { if ( rhs.data != NULL ) rhs.data->AddRef(); if ( data != NULL ) data->Release(); data = rhs.data ; return * this ; } // This member template constructor allows you to // instance a variant_t object with a value of any type. template<typename T> variant_t ( T v ) : data ( new Impl<T>(v) ) { data->AddRef() ; } // This generic conversion operator let you retrieve // the value held. To avoid template specialization conflicts, // it returns an instance of type T, which will be a COPY // of the value contained. template<typename T> operator T () const { return CastFromBase<T>( data )->data ; } // This forms returns a REFERENCE and not a COPY, which // will be significant in some cases. template<typename T> const T & get() const { return CastFromBase<T>( data )->data ; } template<typename T> bool is_type() const { return typeid(*data)==typeid(Impl<T>); } template<typename T> bool is_type(T v) const { return typeid(*data)==typeid(v); } private : struct ImplBase { ImplBase() : refs ( 0 ) {} virtual ~ImplBase() {} void AddRef () { refs ++ ; } void Release() { refs -- ; if ( refs == 0 ) delete this ; } size_t refs ; } ; template<typename T> struct Impl : ImplBase { Impl ( T v ) : data ( v ) {} ~Impl () {} T data ; } ; // The following method is static because it doesn't // operate on variant_t instances. template<typename T> static Impl<T>* CastFromBase ( ImplBase* v ) { // This upcast will fail if T is other than the T used // with the constructor of variant_t. Impl<T>* p = dynamic_cast<Impl<T>*> ( v ) ; if ( p == NULL ) throw invalid_argument ( typeid(T).name()+string(" is not a valid type")); return p ; } ImplBase* data ; } ; #endif