Curiously recurring template pattern: Difference between revisions

Content deleted Content added
m History: commas
m Task 70: Update syntaxhighlight tags - remove use of deprecated <source> tags
Line 9:
== General form ==
 
<sourcesyntaxhighlight lang="cpp">
// The Curiously Recurring Template Pattern (CRTP)
template <class T>
Line 20:
// ...
};
</syntaxhighlight>
</source>
 
Some use cases for this pattern are [[Template metaprogramming#Static polymorphism|static polymorphism]] and other metaprogramming techniques such as those described by [[Andrei Alexandrescu]] in ''[[Modern C++ Design]]''.<ref>{{cite book | first=Andrei | last=Alexandrescu | authorlink=Andrei Alexandrescu | title=Modern C++ Design: Generic Programming and Design Patterns Applied | publisher=Addison-Wesley | isbn=0-201-70431-5 | year=2001}}</ref>
Line 29:
Typically, the base class template will take advantage of the fact that member function bodies (definitions) are not instantiated until long after their declarations, and will use members of the derived class within its own member functions, via the use of a [[Type conversion|cast]]; e.g.:
 
<sourcesyntaxhighlight lang="cpp">
template <class T>
struct Base
Line 53:
static void static_sub_func();
};
</syntaxhighlight>
</source>
 
In the above example, note in particular that the function Base<Derived>::interface(), though ''declared'' before the existence of the struct Derived is known by the compiler (i.e., before Derived is declared), is not actually ''instantiated'' by the compiler until it is actually ''called'' by some later code which occurs ''after'' the declaration of Derived (not shown in the above example), so that at the time the function "implementation" is instantiated, the declaration of Derived::implementation() is known.
Line 67:
The main purpose of an object counter is retrieving statistics of object creation and destruction for a given class.<ref>{{cite journal | author=Meyers, Scott | title=Counting Objects in C++ | journal=C/C++ Users Journal | date=April 1998 | url=http://www.drdobbs.com/cpp/counting-objects-in-c/184403484}}</ref> This can be easily solved using CRTP:
 
<sourcesyntaxhighlight lang="cpp">
template <typename T>
struct counter
Line 103:
// ...
};
</syntaxhighlight>
</source>
 
Each time an object of class <code>X</code> is created, the constructor of <code>counter<X></code> is called, incrementing both the created and alive count. Each time an object of class <code>X</code> is destroyed, the alive count is decremented. It is important to note that <code>counter<X></code> and <code>counter<Y></code> are two separate classes and this is why they will keep separate counts of <code>X</code>'s and <code>Y</code>'s. In this example of CRTP, this distinction of classes is the only use of the template parameter (<code>T</code> in <code>counter<T></code>) and the reason why we cannot use a simple un-templated base class.
Line 113:
When the named parameter object pattern is applied to an object hierarchy, things can go wrong. Suppose we have such a base class:
 
<sourcesyntaxhighlight lang="cpp">
class Printer
{
Line 127:
ostream& m_stream;
};
</syntaxhighlight>
</source>
 
Prints can be easily chained:
 
<sourcesyntaxhighlight lang="cpp">
Printer{myStream}.println("hello").println(500);
</syntaxhighlight>
</source>
 
However, if we define the following derived class:
 
<sourcesyntaxhighlight lang="cpp">
class CoutPrinter : public Printer
{
Line 149:
}
};
</syntaxhighlight>
</source>
 
we "lose" the concrete class as soon as we invoke a function of the base:
 
<sourcesyntaxhighlight lang="cpp">
// v----- we have a 'Printer' here, not a 'CoutPrinter'
CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!"); // compile error
</syntaxhighlight>
</source>
 
This happens because 'print' is a function of the base - 'Printer' - and then it returns a 'Printer' instance.
Line 162:
The CRTP can be used to avoid such problem and to implement "Polymorphic chaining":<ref>{{cite web|last1=Arena|first1=Marco|title=Use CRTP for polymorphic chaining|url=https://marcoarena.wordpress.com/2012/04/29/use-crtp-for-polymorphic-chaining/|accessdate=15 March 2017|date=29 April 2012}}</ref>
 
<sourcesyntaxhighlight lang="cpp>
// Base class
template <typename ConcretePrinter>
Line 202:
// usage
CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!");
</syntaxhighlight>
</source>
 
==Polymorphic copy construction==
Line 208:
When using polymorphism, one sometimes needs to create copies of objects by the base class pointer. A commonly used idiom for this is adding a virtual clone function that is defined in every derived class. The CRTP can be used to avoid having to duplicate that function or other similar functions in every derived class.
 
<sourcesyntaxhighlight lang="cpp">
// Base class has a pure virtual function for cloning
class AbstractShape {
Line 236:
class Circle : public Shape<Circle>{};
 
</syntaxhighlight>
</source>
 
This allows obtaining copies of squares, circles or any other shapes by <code>shapePtr->clone()</code>.