Is this a Curiously Recurring Template Pattern?

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 call foo.
  • wrap is forced to return Wrapper<Base>. For derived types, however, it might be more preferable to return Wrapper<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.

4 Likes