derived
is incomplete when you use it as a template argument to base
in its base classes list.
A common workaround is to use a traits class template. Here’s your example, traitsified. This shows how you can use both types and functions from the derived class through the traits.
// Declare a base_traits traits class template:
template <typename derived_t>
struct base_traits;
// Define the base class that uses the traits:
template <typename derived_t>
struct base {
typedef typename base_traits<derived_t>::value_type value_type;
value_type base_foo() {
return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));
}
};
// Define the derived class; it can use the traits too:
template <typename T>
struct derived : base<derived<T> > {
typedef typename base_traits<derived>::value_type value_type;
value_type derived_foo() {
return value_type();
}
};
// Declare and define a base_traits specialization for derived:
template <typename T>
struct base_traits<derived<T> > {
typedef T value_type;
static value_type call_foo(derived<T>* x) {
return x->derived_foo();
}
};
You just need to specialize base_traits
for any types that you use for the template argument derived_t
of base
and make sure that each specialization provides all of the members that base
requires.