Help with custom smart pointer const correctness

Given the class design below, and the ObjectPtr smart pointer implementation, I can't instantiate ObjectPtr<T> with T = const Car because a const Car returns a shared_ptr<const CarIdent> from the ident() methods, not a shared_ptr<CarIdent> as currently implemented (see compile error at the end of this post. VS2005).
From my very limited meta-programming experience, I'm guessing I need to fix the current typedef shared_ptr<ident_type> ident_ptr; in ObjectPtr to somehow use MPL to "return" shared_ptr<typename T::ident_type const> given a const T, and shared_ptr<typename T::ident_type> given a T, but I don't know how to do that yet.
If someone would be kind enough to point me in the right direction, I'd appreciate. Thanks, --DD #include <boost/static_assert.hpp> #include <boost/type_traits/is_base_of.hpp> #include <boost/shared_ptr.hpp> #include <boost/cast.hpp> #include <string> using namespace std; using namespace boost; class Object; class Ident { public: Object* object() const { return object_; } protected: Ident() : object_(0) {} ~Ident() {} friend class Object; void set_object(Object* e); private: Object* object_; }; typedef shared_ptr<Ident> IdentPtr; typedef shared_ptr<const Ident> ConstIdentPtr; class Object { public: ConstIdentPtr ident() const { return ident_; } const IdentPtr& ident() { return ident_; } protected: Object(shared_ptr<Ident> ident) : ident_(ident) { ident_->set_object(this); } virtual ~Object() { ident_->set_object(0); } private: shared_ptr<Ident> ident_; }; void Ident::set_object(Object* obj) { BOOST_ASSERT((!object_ && obj) || (object_ && !obj)); BOOST_ASSERT(!obj || obj->ident().get() == this); object_ = obj; } template <class T> shared_ptr<typename T::ident_type> ident_of(T* t) { BOOST_STATIC_ASSERT((is_base_of<Object, T>::value)); return static_pointer_cast<typename T::ident_type>(t->ident()); } template <class T> shared_ptr<typename T::ident_type const> ident_of(const T* t) { BOOST_STATIC_ASSERT((is_base_of<Object, T>::value)); return static_pointer_cast<typename T::ident_type const>(t->ident()); } template <class T> class ObjectPtr { public: typedef T object_type; // TODO remove constness typedef typename T::ident_type ident_type; typedef shared_ptr<ident_type> ident_ptr; // TODO: make const correct public: // this Ctor fails to compile if passing a const Car for example. // TODO: figure out (MPL? enable_if?) the correct ident_ptr type // based on the constness of T explicit ObjectPtr(T* obj) : ident_(ident_of(obj)) {} T* get() { return polymorphic_downcast<T*>(ident_->object()); } T* operator->() { get(); } T& operator*() { *get(); } ident_ptr ident() const { return ident_; } // TODO: Safe-Bool idiom // TODO: implicit conversion from ObjectPtr<T> to ObjectPtr<const T>? private: ident_ptr ident_; }; struct CarIdent : public Ident { string make, model; CarIdent(const string& make, const string& model) : make(make), model(model) {} }; class Car : public Object { public: typedef CarIdent ident_type; Car(const string& make, const string& model) : Object(shared_ptr<CarIdent>(new CarIdent(make, model))) {} }; void const_correct_smart_ptr(int /*argc*/, const char* /*argv*/[]) { ObjectPtr<Car> z(new Car("Nissan", "350Z")); ident_of(z.get())->model = "370Z"; // TODO: fix ident_of for smart pointers to avoid .get() // This fails to compile with: error C2664: // 'boost::shared_ptr<T>::shared_ptr(const boost::shared_ptr<T> &)' : // cannot convert parameter 1 from 'boost::shared_ptr<const Car::ident_type>' // to 'const boost::shared_ptr<CarIdent> &' // instantiated from explicit ObjectPtr(T* obj) : ident_(ident_of(obj)) {} ObjectPtr<const Car> zz(new Car("Ford", "Mustang")); }

On Wed, Apr 15, 2009 at 4:16 PM, Dominique Devienne <ddevienne@gmail.com> wrote:
From my very limited meta-programming experience, I'm guessing I need to fix the current typedef shared_ptr<ident_type> ident_ptr; in ObjectPtr to somehow use MPL to "return" shared_ptr<typename T::ident_type const> given a const T, and shared_ptr<typename T::ident_type> given a T, but I don't know how to do that yet.
If someone would be kind enough to point me in the right direction, I'd appreciate. Thanks, --DD
I figured the following which seems to work fine. Didn't think I could do it on my own in 15min, thus my post ;) --DD #include <boost/type_traits/is_const.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/mpl/if.hpp> template <class T> class ObjectPtr { public: typedef typename remove_const<T>::type object_type; typedef typename object_type::ident_type ident_type; typedef shared_ptr< typename mpl::if_c<is_const<T>::value, ident_type const, ident_type>::type > ident_ptr; public: ident_ptr ident() const { return ident_; } private: ident_ptr ident_; };
participants (1)
-
Dominique Devienne