Curiously recurring template pattern: Difference between revisions

Content deleted Content added
Drudru (talk | contribs)
AnomieBOT (talk | contribs)
m Dating maintenance tags: {{Clarify}}
 
(207 intermediate revisions by more than 100 users not shown)
Line 1:
{{Short description|Software design pattern}}
The '''curiously recurring template pattern''' ('''CRTP''') is a [[C++]] idiom in which a class <code>X</code> derives from a class template instantiation using <code>X</code> itself as template argument. The name of this idiom was coined by Coplien{{ref|Coplien}}, who had observed it in some of the earliest [[C++]] template code.
{{Use dmy dates|date=December 2021}}
The '''curiously recurring template pattern''' ('''CRTP''') is an idiom, originally in [[C++]], in which a class <code>X</code> derives from a class [[Template (C++)|template]] instantiation using <code>X</code> itself as a template argument.<ref>{{cite book | first1=David | last1=Abrahams | authorlink1=David Abrahams (computer programmer) | first2=Aleksey | last2=Gurtovoy | title=C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond |publisher=Addison-Wesley | isbn=0-321-22725-5| date=January 2005 }}</ref> More generally it is known as '''F-bound polymorphism''', and it is a form of [[F-bounded quantification|''F''-bounded quantification]].
 
==ExampleHistory==
The technique was formalized in 1989 as "''F''-bounded quantification."<ref>{{cite web|url=http://cs.utexas.edu/~wcook/papers/FBound89/CookFBound89.pdf|title=F-Bounded Polymorphism for Object-Oriented Programming|author=William Cook|date=1989|display-authors=etal}}</ref> The name "CRTP" was independently coined by [[Jim Coplien]] in 1995,<ref>{{cite journal | author=Coplien, James O. | title=Curiously Recurring Template Patterns | journal=C++ Report | date=February 1995 | pages=24–27 | url=https://drive.google.com/file/d/1yJPlJ2d_79gxEzicliT_M2Qn2dwOfCOP/view}}</ref> who had observed it in some of the earliest [[C++]] template code as well as in code examples that Timothy Budd created in his multiparadigm language Leda.<ref>{{cite book | first=Timothy | last=Budd | authorlink=| title=Multiparadigm programming in Leda | publisher=Addison-Wesley | isbn=0-201-82080-3 | year=1994| title-link=Multiparadigm programming in Leda }}</ref> It is sometimes called "Upside-Down Inheritance"<ref>{{Cite web|url=http://www.apostate.com/programming/atlupsidedown.html |title=Apostate Café: ATL and Upside-Down Inheritance |date=2006-03-15 |access-date=2016-10-09 |url-status=bot: unknown |archiveurl=https://web.archive.org/web/20060315072824/http://www.apostate.com/programming/atlupsidedown.html |archivedate=15 March 2006 }}</ref><ref>{{Cite web|url=http://archive.devx.com/free/mgznarch/vcdj/1999/julmag99/atlinherit1.asp |title=ATL and Upside-Down Inheritance |date=2003-06-04 |access-date=2016-10-09 |url-status=bot: unknown |archiveurl=https://web.archive.org/web/20030604104137/http://archive.devx.com/free/mgznarch/vcdj/1999/julmag99/atlinherit1.asp |archivedate=4 June 2003 }}</ref> due to the way it allows class hierarchies to be extended by substituting different base classes.
// The Curiously Recurring Template Pattern (CRTP)
struct derived : base<derived>
{
// ...
};
 
The Microsoft Implementation of CRTP in [[Active Template Library]] (ATL) was independently discovered, also in 1995, by Jan Falkin, who accidentally derived a base class from a derived class. Christian Beaumont first saw Falkin's code and initially thought it could not compile in the Microsoft compiler available at the time. Following the revelation that it did work, Beaumont based the entire ATL and [[Windows Template Library]] (WTL) design on this mistake.{{Citation needed|date=August 2018}}
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 <code>static_cast</code>, or simply a cast e.g.:
 
== General form ==
template <class Derived>
struct base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
 
<syntaxhighlight lang="cpp">
struct derived : base<derived>
// The Curiously Recurring Template Pattern (CRTP)
{
template <class T>
void implementation();
class Base
static void static_sub_func();
{
};
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
</syntaxhighlight>{{clarify|reason=members within Base<T> can use what template and what would that look like?|date=June 2025}}
 
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>
This technique achieves a similar effect to the use of virtual functions, without the costs (and some flexibility) of dynamic polymorphism. This particular use of the CRTP has been called "simulated dynamic binding" by [http://www.pnotepad.org/devlog/archives/000083.html some]. This pattern is used extensively in the Windows [[Active Template Library|ATL]] and [[WTL]] libraries.
It also figures prominently in the C++ implementation of the [[Data, Context, and Interaction]] paradigm.<ref>{{cite book | first1=James | last1=Coplien | authorlink1=James Coplien | first2=Gertrud | last2=Bjørnvig | title=Lean Architecture: for agile software development | publisher=Wiley | isbn=978-0-470-68420-7 | year=2010}}</ref>
In addition, CRTP is used by the C++ standard library to implement the <code>std::enable_shared_from_this</code> functionality.<ref>{{cite web |title=std::enable_shared_from_this |url=https://en.cppreference.com/w/cpp/memory/enable_shared_from_this |access-date=22 November 2022}}</ref>
 
== Static polymorphism ==
To elaborate on the above example, consider a base class with '''no virtual functions'''. Whenever the base class calls another member function, it will always call its own base class functions. When we inherit from this class, a derived class, we inherit all the member variables and member functions that weren't overridden (no constructors or destructors, of course, either). If the derived class calls an inherited function that then calls another member function, that function will never call any derived or overridden member functions in the derived class. As a result of this behavior, most C++ programmers define member functions as virtual to avoid this problem.
 
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.:
However, if base class member functions use the CRTP pattern for all member function calls, the overridden functions in the derived class will get selected at compile time. This effectively emulates the virtual function call system at compile time without the costs in size or function call overhead ([[VTBL]] structures, and method lookups, multiple-inheritance VTBL machinery) and the slight disadvantage of not being able to do this choice at runtime.
 
<syntaxhighlight lang="cpp">
==See also==
template <class T>
struct Base
{
void interface()
{
// ...
static_cast<T*>(this)->implementation();
// ...
}
 
static void static_func()
* [[Barton-Nackman trick]]
{
// ...
T::static_sub_func();
// ...
}
};
 
struct Derived : public Base<Derived>
{
void implementation();
static void static_sub_func();
};
</syntaxhighlight>
 
In the above example, the function <code>Base<Derived>::interface()</code>, though ''declared'' before the existence of the <code>struct Derived</code> is known by the compiler (i.e., before <code>Derived</code> is declared), is not actually ''instantiated'' by the compiler until it is actually ''called'' by some later code which occurs ''after'' the declaration of <code>Derived</code> (not shown in the above example), so that at the time the function "interface" is instantiated, the declaration of <code>Derived::implementation()</code> is known.
 
This technique achieves a similar effect to the use of [[virtual function]]s, without the costs (and some flexibility) of [[dynamic polymorphism]]. This particular use of the CRTP has been called "simulated dynamic binding" by some.<ref>{{cite web | url=http://www.pnotepad.org/devlog/archives/000083.html | title=Simulated Dynamic Binding | date=7 May 2003 | accessdate=13 January 2012 | url-status=dead | archiveurl=https://web.archive.org/web/20120209045146/http://www.pnotepad.org/devlog/archives/000083.html | archivedate=9 February 2012 }}</ref> This pattern is used extensively in the Windows [[Active Template Library|ATL]] and [[Windows Template Library|WTL]] libraries.
 
To elaborate on the above example, consider a base class with '''no virtual functions'''. Whenever the base class calls another member function, it will always call its own base class functions. When we derive a class from this base class, we inherit all the member variables and member functions that were not overridden (no constructors or destructors). If the derived class calls an inherited function which then calls another member function, then that function will never call any derived or overridden member functions in the derived class.
 
However, if base class member functions use CRTP for all member function calls, the overridden functions in the derived class will be selected at compile time. This effectively emulates the virtual function call system at compile time without the costs in size or function call overhead ([[Virtual method table|VTBL]] structures, and method lookups, multiple-inheritance VTBL machinery) at the disadvantage of not being able to make this choice at runtime.
 
== Object counter ==
 
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:
 
<syntaxhighlight lang="cpp">
template <typename T>
struct counter
{
static inline int objects_created = 0;
static inline int objects_alive = 0;
 
counter()
{
++objects_created;
++objects_alive;
}
counter(const counter&)
{
++objects_created;
++objects_alive;
}
protected:
~counter() // objects should never be removed through pointers of this type
{
--objects_alive;
}
};
 
class X : counter<X>
{
// ...
};
 
class Y : counter<Y>
{
// ...
};
</syntaxhighlight>
 
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.
 
== Polymorphic chaining ==
 
[[Method chaining]], also known as named parameter idiom, is a common syntax for invoking multiple method calls in object-oriented programming languages. Each method returns an object, allowing the calls to be chained together in a single statement without requiring variables to store the intermediate results.
 
When the named parameter object pattern is applied to an object hierarchy, things can go wrong. Suppose we have such a base class:
 
<syntaxhighlight lang="cpp">
class Printer
{
public:
Printer(ostream& pstream) : m_stream(pstream) {}
template <typename T>
Printer& print(T&& t) { m_stream << t; return *this; }
template <typename T>
Printer& println(T&& t) { m_stream << t << endl; return *this; }
private:
ostream& m_stream;
};
</syntaxhighlight>
 
Prints can be easily chained:
 
<syntaxhighlight lang="cpp">
Printer(myStream).println("hello").println(500);
</syntaxhighlight>
 
However, if we define the following derived class:
 
<syntaxhighlight lang="cpp">
class CoutPrinter : public Printer
{
public:
CoutPrinter() : Printer(cout) {}
 
CoutPrinter& SetConsoleColor(Color c)
{
// ...
return *this;
}
};
</syntaxhighlight>
 
we "lose" the concrete class as soon as we invoke a function of the base:
 
<syntaxhighlight lang="cpp">
// v----- we have a 'Printer' here, not a 'CoutPrinter'
CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!"); // compile error
</syntaxhighlight>
 
This happens because 'print' is a function of the base – 'Printer' – and then it returns a 'Printer' instance.
 
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>
 
<syntaxhighlight lang="cpp>
// Base class
template <typename ConcretePrinter>
class Printer
{
public:
Printer(ostream& pstream) : m_stream(pstream) {}
template <typename T>
ConcretePrinter& print(T&& t)
{
m_stream << t;
return static_cast<ConcretePrinter&>(*this);
}
template <typename T>
ConcretePrinter& println(T&& t)
{
m_stream << t << endl;
return static_cast<ConcretePrinter&>(*this);
}
private:
ostream& m_stream;
};
// Derived class
class CoutPrinter : public Printer<CoutPrinter>
{
public:
CoutPrinter() : Printer(cout) {}
CoutPrinter& SetConsoleColor(Color c)
{
// ...
return *this;
}
};
// usage
CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!");
</syntaxhighlight>
 
==Polymorphic copy construction==
 
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.
 
<syntaxhighlight lang="cpp">
// Base class has a pure virtual function for cloning
class AbstractShape {
public:
virtual ~AbstractShape () = default;
virtual std::unique_ptr<AbstractShape> clone() const = 0;
};
 
// This CRTP class implements clone() for Derived
template <typename Derived>
class Shape : public AbstractShape {
public:
std::unique_ptr<AbstractShape> clone() const override {
return std::make_unique<Derived>(static_cast<Derived const&>(*this));
}
 
protected:
// We make clear Shape class needs to be inherited
Shape() = default;
Shape(const Shape&) = default;
Shape(Shape&&) = default;
};
 
// Every derived class inherits from CRTP class instead of abstract class
 
class Square : public Shape<Square>{};
 
class Circle : public Shape<Circle>{};
 
</syntaxhighlight>
 
This allows obtaining copies of squares, circles or any other shapes by <code>shapePtr->clone()</code>.
 
===Pitfalls===
One issue with static polymorphism is that without using a general base class like <code>AbstractShape</code> from the above example, derived classes cannot be stored homogeneously – that is, putting different types derived from the same base class in the same container. For example, a container defined as <code>std::vector<Shape*></code> does not work because <code>Shape</code> is not a class, but a template needing specialization. A container defined as <code>std::vector<Shape<Circle>*></code> can only store <code>Circle</code>s, not <code>Square</code>s. This is because each of the classes derived from the CRTP base class <code>Shape</code> is a unique type. A common solution to this problem is to inherit from a shared base class with a virtual destructor, like the <code>AbstractShape</code> example above, allowing for the creation of a <code>std::vector<AbstractShape*></code>.
 
==Deducing this==
 
The use of CRTP can be simplified using the [[C++23]] feature ''deducing this''.<ref>{{Cite web|url=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html|title=Deducing this|date=2021-07-12|author1=Gašper Ažman|author2=Sy Brand|author3=Ben Deane|author4=Barry Revzin
}}</ref><ref>{{Cite web|title=Explicit object parameter|url=https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter|access-date=27 December 2023}}</ref> For the function <code>signature_dish</code> to call a derived member function <code>cook_signature_dish</code>, <code>ChefBase</code> needs to be a templated type and <code>CafeChef</code> needs to inherit from <code>ChefBase</code>, passing its type as the template parameter.
 
<syntaxhighlight lang="cpp">
 
template <typename T>
struct ChefBase
{
void signature_dish()
{
static_cast<T*>(this)->cook_signature_dish();
}
};
 
struct CafeChef : ChefBase<CafeChef>
{
void cook_signature_dish() {}
};
 
</syntaxhighlight>
 
If explicit object parameter is used, <code>ChefBase</code> does not need to be templated and <code>CafeChef</code> can derive from <code>ChefBase</code> plainly. Since the <code>self</code> parameter is automatically deduced as the correct derived type, no casting is required.
 
<syntaxhighlight lang="cpp">
 
struct ChefBase
{
template <typename Self>
void signature_dish(this Self&& self)
{
self.cook_signature_dish();
}
};
 
struct CafeChef : ChefBase
{
void cook_signature_dish() {}
};
 
 
</syntaxhighlight>
 
==See also==
* [[Barton–Nackman trick]]
* [[Bounded quantification#F-bounded quantification|F-bounded quantification]]
 
==References==
{{reflist}}
* {{note|Coplien}}{{cite journal | author=Coplien, James O. | title=Curiously Recurring Template Patterns | journal=C++ Report | year=1995, February | pages=24–27}}
 
{{C++ programming language}}
 
[[Category:Software design patterns]]
[[Category:C++]]
[[Category:Articles with example C++ code]]