Summary
The boost::any type is a very important type in that it can hold any object which has a copy-constructor. However if you don't want to hold a copy of the value you can instead refer to the object using the ootl::any_ptr type.
Advertisement
My ootl::any_ptr class can point to any object with a copy-constructor, and provides the following public functions:
// this class can point to any copy-constructible value_type
// and let you clone or delete it safely
class any_ptr
{
public:
// forward declarations
template <class T>
struct functions;
template <class T>
any_ptr(T* x)
: m_a(x), m_t(&functions<T>::table)
{}
any_ptr()
: m_a(NULL), m_t(NULL)
{}
void Delete() {
assert(m_a != NULL);
m_t->Delete(m_a);
m_a = NULL;
}
any_ptr Clone() const {
any_ptr o(*this);
o.m_a = m_t->Clone(m_a);
return o;
}
const std::type_info& GetType() const {
return m_t->GetType(m_a);
}
template<typename ValueType>
ValueType* PtrCast() {
if (!(typeid(ValueType) == GetType())) {
throw BadObjectCast();
}
return static_cast<ValueType*>(m_a);
}
// Function table type
// order is important, must match all other lists of functions
struct table {
void (*Delete)(void*);
const std::type_info& (*GetType)(void*);
void* (*Clone)(void*);
};
// For a given referenced type T, generates functions for the
// function table and a static instance of the table.
template<class T>
struct functions
{
static typename any_ptr::table table;
static void Delete(void* p) {
delete static_cast<T*>(p);
}
static const std::type_info& GetType(void* p) {
return typeid(T);
}
static void* Clone(void* p) {
return new T(*static_cast<T*>(p));
}
};
private:
void* m_a;
table* m_t;
};
template<class T>
typename any_ptr::table
any_ptr::functions<T>::table = {
&any_ptr::template functions<T>::Delete
,&any_ptr::template functions<T>::GetType
,&any_ptr::template functions<T>::Clone
};
Those paying close attention to my work, and not intimidated by complex template code, may realize that lately I have been riding in to town with the same horse, but painting it different colors.
What I mean to say is that the basic idea is always the same, create a function pointer table at compile time for every assignment or copy-construction to a different type. Each generated function in the table is responsible for casting the internal pointer to the appropriate type.
Hopefully all this makes some sense, and industrious readers can contribute some interesting applications of this class and/or technique.
Christopher, I found any_ptr faster than boost::any and simple enough to use in my current project. Thank you.
I found that two any_ptr's for the same type but in different dll's have different m_t (table address). (I'm not very sure about it but it explained the problem I had that time.) I think that was why you had to use typeid to compare types instead of comparing the value of m_t's.
But, if so, any_ptr's copy constructor (implicit) might work incorrectly in that environment, therefore, so does Clone().