Curiously recurring template pattern: Difference between revisions

Content deleted Content added
No edit summary
Add simplified CRTP with C++23 feature, deducing this
Line 244:
===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 it's 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==