Reputation: 5122
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?
Upvotes: 3
Views: 317
Reputation: 93264
void common_with_arg(typename D::Arg arg)
// ^^^^^^
You cannot access D::Arg
here, as the definition of Derived
would be required. But the definition is never available as the Base
template is being instantiated here...
struct Derived : Base<Derived> {
// ^^^^^^^^^^^^^
...where Derived
is not yet fully-defined.
One possible workaround is making common_with_arg
a function template:
template <typename T>
void common_with_arg(T&& arg) {
// ... do something ...
static_cast<D *>(this)->impl_with_arg(std::forward<T>(arg));
// ... do something more ...
}
If you really need the Arg
type alias, read this question:
"C++ static polymorphism (CRTP) and using typedefs from derived classes".
Upvotes: 5