|
Boost Users : |
Subject: [Boost-users] Help with custom smart pointer const correctness
From: Dominique Devienne (ddevienne_at_[hidden])
Date: 2009-04-15 17:16:53
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"));
}
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