16.3 The Curiously Recurring Template Pattern (CRTP)

Ru-Brd

This oddly named pattern refers to a general class of techniques that consists of passing a derived class as a template argument to one of its own base classes. In its simplest form, C++ code for such a pattern looks as follows :

 template <typename Derived>  class CuriousBase {   };  class Curious : public CuriousBase<Curious> {   }; 

Our first outline of CRTP shows a nondependent base class: The class Curious is not a template and is therefore immune to some of the name visibility issues of dependent base classes. However, this is not an intrinsic characteristic of CRTP. Indeed, we could just as well have used the following alternative outline:

 template <typename Derived>  class CuriousBase {   };  template <typename T>  class CuriousTemplate : public CuriousBase<CuriousTemplate<T> > {   }; 

From this outline, however, it is not a far stretch to propose yet another alternative formulation, this time involving a template template parameter:

 template <template<typename> class Derived>  class MoreCuriousBase {   };  template <typename T>  class MoreCurious : public MoreCuriousBase<MoreCurious> {   }; 

A simple application of CRTP consists of keeping track of how many objects of a certain class type were created. This is easily achieved by incrementing an integral static data member in every constructor and decrementing it in the destructor. However, having to provide such code in every class is tedious . Instead, we can write the following template:

  // inherit/objectcounter.hpp  #include <stddef.h>  template <typename CountedType>  class ObjectCounter {    private:      static size_t count;  // number of existing objects  protected:  // default constructor  ObjectCounter() {          ++ObjectCounter<CountedType>::count;      }  // copy constructor  ObjectCounter (ObjectCounter<CountedType> const&) {          ++ObjectCounter<CountedType>::count;      }  // destructor  ~ObjectCounter() {          --ObjectCounter<CountedType>::count;      }    public:  // return number of existing objects:  static size_t live() {          return ObjectCounter<CountedType>::count;      }  };  // initialize counter with zero  template <typename CountedType>  size_t ObjectCounter<CountedType>::count = 0; 

If we want to count the number of live (that is, not yet destroyed ) objects for a certain class type, it suffices to derive the class from the ObjectCounter template. For example, we can define and use a counted string class along the following lines:

  // inherit/testcounter.cpp  #include "objectcounter.hpp"  #include <iostream>  template <typename CharT>  class MyString : public ObjectCounter<MyString<CharT> > {   };  int main()  {      MyString<char> s1, s2;      MyString<wchar_t> ws;      std::cout << "number of MyString<char>: "                << MyString<char>::live() << std::endl;      std::cout << "number of MyString<wchar_t>: "                << ws.live() << std::endl;  } 

In general, CRTP is useful to factor out implementations of interfaces that can only be member functions (for example, constructor, destructors, and subscript operators).

Ru-Brd


C++ Templates
C++ Templates: The Complete Guide
ISBN: 0201734842
EAN: 2147483647
Year: 2002
Pages: 185

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net