Here's a minimal version of what I'm trying to do:
template<typename D>
struct Base {
void common() {
// ... do something ...
static_cast<D *>(this)->impl();
// ... do something ...
}
void common_with_arg(typename D::Arg arg) {
// ... do something ...
static_cast<D *>(this)->impl_with_arg(arg);
// ... do something more ...
}
};
struct Derived : Base<Derived> {
void impl() { }
using Arg = int;
void impl_with_arg(Arg arg) { }
};
Base::common()
and Derived::impl()
work OK (as expected).
Base::common_with_arg()
and Derived::impl_with_arg()
, however, do not.
With gcc, for example, I get the following error:
1.cc: In instantiation of ‘struct Base<Derived>’:
1.cc:18:18: required from here
1.cc:11:7: error: invalid use of incomplete type ‘struct Derived’
void common_with_arg(typename D::Arg arg) {
^~~~~~~~~~~~~~~
1.cc:18:8: note: forward declaration of ‘struct Derived’
struct Derived : Base<Derived> {
Intuitively (without understanding all details about template instantiation), this seems like a sensible error. Is there another way to achieve the same functionality?
You cannot access
D::Arg
here, as the definition ofDerived
would be required. But the definition is never available as theBase
template is being instantiated here......where
Derived
is not yet fully-defined.One possible workaround is making
common_with_arg
a function template:example on wandbox
If you really need the
Arg
type alias, read this question:"C++ static polymorphism (CRTP) and using typedefs from derived classes".