What is CRTP(Curiously recurring template pattern) ?
The curiously recurring template pattern (CRTP) is an idiom in C++ in which a class X derives from a class template instantiation using X itself as template argument.
Some use cases for this pattern are static polymorphism and other metaprogramming techniques such as those described by Andrei Alexandrescu in Modern C++ Design.
General form
// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
{
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
Static polymorphism
template <class T>
struct Base
{
void interface()
{
// ...
static_cast<T*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
T::static_sub_func();
// ...
}
};
struct Derived : public Base<Derived>
{
void implementation();
static void static_sub_func();
};
Dynamic polymorphism vs. Static polymorphism(CRTP)
// http://www.geeksforgeeks.org/curiously-recurring-template-pattern-crtp-2/
// A simple C++ program to demonstrate run-time
// polymorphism
#include <iostream>
#include <chrono>
using namespace std;
typedef std::chrono::high_resolution_clock Clock;
namespace DynamicPolymorphism {
// To store dimensions of an image
class Dimension
{
public:
Dimension(int _X, int _Y) {mX = _X; mY = _Y; }
private:
int mX, mY;
};
// Base class for all image types
class Image
{
public:
virtual void Draw() = 0;
virtual Dimension GetDimensionInPixels() = 0;
protected:
int dimensionX;
int dimensionY;
};
// For Tiff Images
class TiffImage : public Image
{
public:
void Draw() { }
Dimension GetDimensionInPixels() {
return Dimension(dimensionX, dimensionY);
}
};
// There can be more derived classes like PngImage,
// BitmapImage, etc
// Driver code that calls virtual function
int main()
{
// An image type
Image* pImage = new TiffImage;
// Store time before virtual function calls
auto then = Clock::now();
// Call Draw 1000 times to make sure performance
// is visible
for (int i = 0; i < 1000; ++i)
pImage->Draw();
// Store time after virtual function calls
auto now = Clock::now();
cout << "Dynamic Polymorphism - Time taken: "
<< std::chrono::duration_cast
<std::chrono::nanoseconds>(now - then).count()
<< " nanoseconds" << endl;
return 0;
}
}
//
// Converted to StaticPolymorphism
//
namespace StaticPolymorphism {
// Image program (similar to above) to demonstrate
// working of CRTP
// To store dimensions of an image
class Dimension
{
public:
Dimension(int _X, int _Y)
{
mX = _X;
mY = _Y;
}
private:
int mX, mY;
};
// Base class for all image types. The template
// parameter T is used to know type of derived
// class pointed by pointer.
template <class T>
class Image
{
public:
void Draw()
{
// Dispatch call to exact type
static_cast<T*> (this)->Draw();
}
Dimension GetDimensionInPixels()
{
// Dispatch call to exact type
static_cast<T*> (this)->GetDimensionInPixels();
}
protected:
int dimensionX, dimensionY;
};
// For Tiff Images
class TiffImage : public Image<TiffImage>
{
public:
void Draw()
{
// Uncomment this to check method dispatch
// cout << "TiffImage::Draw() called" << endl;
}
Dimension GetDimensionInPixels()
{
return Dimension(dimensionX, dimensionY);
}
};
// There can be more derived classes like PngImage,
// BitmapImage, etc
// Driver code
int main()
{
// An Image type pointer pointing to Tiffimage
Image<TiffImage>* pImage = new TiffImage;
// Store time before virtual function calls
auto then = Clock::now();
// Call Draw 1000 times to make sure performance
// is visible
for (int i = 0; i < 1000; ++i)
pImage->Draw();
// Store time after virtual function calls
auto now = Clock::now();
cout << "Static Polymorphism - Time taken: "
<< std::chrono::duration_cast
<std::chrono::nanoseconds>(now - then).count()
<< " nanoseconds" << endl;
return 0;
}
}
int main() {
DynamicPolymorphism::main();
StaticPolymorphism::main();
}
Results after executing
Dynamic Polymorphism - Time taken: 1105 nanoseconds
Static Polymorphism - Time taken: 45 nanoseconds
Conclusion
Sometimes we can choose the Static polymorphism instead of the Dynamic polymorphism to enhance a performance for algorithm or your libraries.
Reference
Wikimedia: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern http://www.geeksforgeeks.org/curiously-recurring-template-pattern-crtp-2/