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_twicemust use dynamic dispatch to callfoo. -
wrapis 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.