[Boost-users] Help with custom smart pointer const correctness

5 views
Skip to first unread message

Dominique Devienne

unread,
Apr 15, 2009, 5:16:53 PM4/15/09
to boost-users
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 mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Dominique Devienne

unread,
Apr 15, 2009, 5:56:30 PM4/15/09
to boost-users
On Wed, Apr 15, 2009 at 4:16 PM, Dominique Devienne <ddev...@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_;

Reply all
Reply to author
Forward
0 new messages