The dynamic cast is failing because the classes that are instantiations of ObjectProxy do not share the same hierarchy as the types given in the parameterisation of ObjectProxy. I see two approaches that may help. One, you make the types given to ObjectProxy share a single common base class and move the dynamic cast away from ObjectProxy and onto the instances.
namespace approach2 {
struct object_t {
virtual ~object_t() { }
};
struct required_base_t {
virtual ~required_base_t() { }
};
class object_proxy_base_t : public object_t {
required_base_t* instance_;
public:
object_proxy_base_t(required_base_t* i) : instance_ (i) { }
template <class T>
T* cast_to() const
{
return dynamic_cast<T*>(instance_);
}
};
template <class value_t>
class object_proxy_t : public object_proxy_base_t {
value_t* instance_;
public:
object_proxy_t(value_t* i)
: object_proxy_base_t (i),
instance_ (i)
{
}
};
template <class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_t<value_t>(new value_t(value));
}
struct parent_t : required_base_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy(parent_t());
object_t* b = new_with_proxy(child_t());
std::cout
<< dynamic_cast<object_proxy_base_t*>(a)->cast_to<parent_t>() << '\n' // works
<< dynamic_cast<object_proxy_base_t*>(b)->cast_to<parent_t>() << '\n' // works
;
}
}
This approach is not possible if you cannot change the base classes of all types used by ObjectProxy. Which leads to the second solution where you make ObjectProxy instantiations have the same hierarchy as the types used to parameterise it.
namespace approach3 {
struct object_t {
virtual ~object_t() { }
};
struct empty_t {
template <class T>
empty_t(T*) { }
};
template <class value_t>
class object_proxy_t : public virtual object_t {
value_t* instance_;
public:
object_proxy_t(value_t* i) : instance_ (i) { }
};
template <class value_t, class base_t>
class object_proxy_sub_t :
public object_proxy_t<value_t>,
public base_t {
public:
object_proxy_sub_t(value_t* i)
: object_proxy_t<value_t>(i),
base_t (i)
{
}
};
template <class base_t, class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_sub_t<value_t, base_t>(new value_t(value));
}
struct parent_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy<empty_t>(parent_t());
object_t* b = new_with_proxy<object_proxy_t<parent_t> >(child_t());
std::cout
<< dynamic_cast<object_proxy_t<parent_t>*>(a) << '\n' // works
<< dynamic_cast<object_proxy_t<parent_t>*>(b) << '\n' // works
;
}
}
This approach places fewer requirements on the types involved but means more work to keep the hierarchies in sync.