C++: The curiously recurring template pattern

Let’s consider the following class:

class Writer
{
  public:
    Writer() { }
    virtual ~Writer() { }

    virtual void write(const char* aStr) const = 0;
};

This class will be useful as the base class for implementing several specialized writers (a file writer and a console writer come to my mind right now), for instance:

class FileWriter : public Writer
{
  public:
    FileWriter(FILE* aFile) { mFile = aFile; }
    virtual ~FileWriter() { fclose(mFile); }

    virtual void write(const char* aStr) const
    {
      fprintf(mFile, "%s\n", aStr);
    }

  private:
    FILE* mFile;
};

class ConsoleWriter : public Writer
{
  public:
    ConsoleWriter() { }
    virtual ~ConsoleWriter() { }

    virtual void write(const char* aStr) const
    {
      printf("%s\n", aStr);
    }
};

Nice, isn’t it? We can use the Writer::write() method to write on any kind of media depending on the subclass we implement. So, what is the problem here? PERFORMANCE: Your application must decide, in runtime, what implementation of your method must be executed and it takes some time.

The “curiously recurring template pattern” (CRTP) is a very elegant way of implement something called “static polymorphism”; using “static polymorphism” your application will not need to decide the method implementation to be executed, because that decision will be taken by…….. THE COMPILER!

The idea of the CRTP idiom is:

  1. Creating a template class Base that will be used as a base class.
  2. Implementing the method that will call to the wanted method implemented in the child class.
  3. Creating a subclass Child : Base (T = Child… that is why this is called “recurring”)
  4. Implementing the wanted method in the child class.

So, my example could be converted to:

template <class T>
class Writer
{
  public:
    Writer()  { }
    ~Writer()  { }

    void write(const char* str) const
    {
      static_cast<const T*>(this)->writeImpl(str); //here the magic is!!!
    }
};

class FileWriter : public Writer<FileWriter>
{
  public:
    FileWriter(FILE* aFile) { mFile = aFile; }
    ~FileWriter() { fclose(mFile); }

    //here comes the implementation of the write method on the subclass
    void writeImpl(const char* str) const
    {
      fprintf(mFile, "%s\n", str);
    }

  private:
    FILE* mFile;
};


class ConsoleWriter : public Writer<ConsoleWriter>
{
  public:
    ConsoleWriter() { }
    ~ConsoleWriter() { }

    void writeImpl(const char* str) const
    {
      printf("%s\n", str);
    }
};

And we could use it in this way:

int main()
{
  FILE* file;
  file = fopen("file.txt", "w");
  FileWriter writer(file);
  writer.write("Hello world");
  return 0;
}

As you can see in this last example, the Writer::write() method behaves like the virtual method written in my first example, but the binding is done in compile time, thus, the performance of
calling a method using this pattern is better than implementing everything in the “normal” way.

Obviously, you do not have the flexibility of dynamic polymorphism, but this idiom can be very useful if you want to create some classes with a basic functionality, create the subclasses with a more specific functionality and use them with no performance cost added.

Advertisements

6 thoughts on “C++: The curiously recurring template pattern

  1. But there is a caveat: the called method must be PUBLIC, otherwise it won’t compile. If your class design had to call a protected/private method, you’ll have to mess the design to make the method public.

  2. I have read quite a few posts about CRTP recently, but they all seem to focus on the building the class hierarchy rather than using it. Could you come up with some more realistic example, that benefits from the CRTP? Cause your main function would work even if your concrete writers are not inherited from template class Writer. Here’s an example: http://ideone.com/BKK0Ff

    1. In my example, consider the fact you have a class that writes several things to some “lower level” entity (screen, disk, etc). The classes that have that low level knowledge, do not need to deal with all the stuff your “higher level” implementation needs. Remember, templates used in this way provide some traits to the general behavior of the class.

      See my example below, your base class published two extra methods “say_hi” and “say_bye” that should not need to be implemented by the specific writer.

      Do I answer your question? Thanks for reading me!

      #include

      template <class T>
      class Writer
      {
      public:
      Writer() { }
      ~Writer() { }

      void write(const char* str) const
      {
      static_cast<const T*>(this)->writeImpl(str);
      }

      void say_hi() const
      {
      write(“Hi”);
      }

      void say_bye() const
      {
      write(“Bye”);
      }
      };

      class ConsoleWriter : public Writer<ConsoleWriter>
      {
      public:
      ConsoleWriter() { }
      ~ConsoleWriter() { }

      void writeImpl(const char* str) const
      {
      printf(“%s\n”, str);
      }
      };

      class ConsoleWriterNoInheritance
      {
      public:
      ConsoleWriterNoInheritance() { }
      ~ConsoleWriterNoInheritance() { }

      void write(const char* str) const
      {
      printf(“%s\n”, str);
      }
      };

      int main()
      {
      ConsoleWriter writer;
      writer.write(“Hello world”);
      writer.say_hi();
      ConsoleWriterNoInheritance other_writer;
      other_writer.write(“Other”);
      //other_writer.hi(); DOES NOT COMPILE
      return 0;
      }

      1. Thanks, this snippet makes it clearer. This looks like strategy pattern, so I would prefer it to look more like this: http://ideone.com/ZYgwsA because it does not have this awkward inside-out structure, although it is probably a matter of taste and habit.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s