I agree with @trentj.
The CRTP is when you have a type Derived
that inherits from Base<Derived>
. For example
class Base {
virtual void foo() = 0;
void call_foo_twice() {
foo();
foo();
}
Wrapper<Base> wrap() const {
return { *this };
}
}
This snippet showcases a couple of use cases:
-
call_foo_twice
must use dynamic dispatch to callfoo
. -
wrap
is forced to returnWrapper<Base>
. For derived types, however, it might be more preferable to returnWrapper<Derived>
.
The CRTP fixes these problems by letting the type of Derived
be known:
template<typename Derived>
class Base {
virtual void foo() = 0;
void call_foo_twice() {
Derived& derived = static_cast<Derived&>(*this);
foo();
foo();
}
Wrapper<Derived> wrap() const {
Derived& derived = static_cast<const Derived&>(*this);
return { derived };
}
}
But in rust, we don't use base classes for dynamic polymorphism. We use traits. When you implement a trait, you already know the Self
type: (which is effectively the "zeroth" type parameter to every trait)
trait Trait {
fn foo(&mut self);
fn call_foo_twice(&mut self) {
self.foo(); // <-- this is statically dispatched
self.foo();
}
fn wrap(self) -> Wrapper<Self> { // <-- we can name Self
Wrapper(self)
}
}
So by and large, Rust doesn't need the CRTP.