Content deleted Content added
m Disambiguating links to VTBL (link changed to Virtual method table) using DisamAssist. |
m Dating maintenance tags: {{Clarify}} |
||
(10 intermediate revisions by 9 users not shown) | |||
Line 4:
==History==
The technique was formalized in 1989 as "''F''-bounded quantification."<ref>{{cite web|url=http://
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
== General form ==
Line 22 ⟶ 21:
// ...
};
</syntaxhighlight>{{clarify|reason=members within Base<T> can use what template and what would that look like?|date=June 2025}}
</syntaxhighlight>▼
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 51 ⟶ 50:
};
struct Derived : public Base<Derived>
{
void implementation();
Line 58 ⟶ 57:
</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 "
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.
Line 244 ⟶ 243:
===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==
|