SlideShare a Scribd company logo
The CRTP:
Static Polymorphism
and Expression Templates
Francesco Casalegno
In this presentation...
1. Understand the CRTP (Curiously Recurring Template Pattern)
template <class T>
class Animal { … };
class Chicken: public Animal<Chicken> { … };
2. Implement compile-time polymorphism & avoid overhead of virtual functions
// run-time polymorphism
void call_animal(Animal& a) { std::cout << a.call() << std::endl; } // overhead...
// compile-time polymorphism
template <class T>
void call_animal(Animal<T>& a) { std::cout << a.call() << std::endl; } // no overhead!
3. Implement expression templates & avoid useless loops and copies
Vec<double> x(10), y(10), z(10);
Vec<double> tot = x + y * z; // how to avoid 2 loops and 2 copies here?
2
The Curiously Recurring Template Pattern (CRTP)
● A class template (e.g. std::vector<T>, std::map<T1,T2>, … ) defines a family of classes.
● We can also derive a class X from a class template that uses X itself as template parameter!
Does that sound complicated? Easier done than said.
This C++ template construct is called the Curiously Recurring Template Pattern (CRTP).
● Why do we need this curious pattern?
→ static polymorphism: alternative to virtual, avoids memory and execution time overhead
→ expression templates: computes expressions only when needed, removes loops and copies
3
Container<double> u; // container of doubles
Container<char> v; // container of chars
Container<Container<int*> > w; // container of containers of int ptrs
// Container storing objects of some type T
template <class T>
class Container {
T* data_; // buffer containing the data
size_t size_; // buffer's length
};
template <class T>
class Base { … };
class Derived: Base<Derived> { … }; // A curious derivation!
Part 1: Static Polymorphism
4
● The keyword virtual is used to allow a method of a class Base to support dynamic polymorphism.
This means that the method can be overridden in a class Derived, such that any call to the virtual
function from a Base pointer/reference to a Derived object is resolved as if it came from a Derived:
● Dynamic polymorphism can be very useful in the following cases:
→ call a method of Derived from an external function
→ iterate some operation on a vector of pointers to Base
Dynamic Polymorphism
5
struct Animal {
virtual std::string call() const { return "animal call"; }
std::string food() const { return "animal food"; }
};
struct Hen: Animal {
virtual std::string call() const override { return "cluck!"; }
std::string food() const { return "corn"; }
};
// Example of usage
Hen h;
Animal* ptr = &h; ptr->call(); // "cluck!", because call() is an overridden virtual
Animal& ref = h; ref.food(); // "animal food", because food() is not virtual
// pass by reference (or pointer), to allow call to overridden virtual function
void print_call(Animal const& a) { std::cout << a.call() << std::endl; }
Hen h; print_call(h); // prints "cluck!"
Rooster r; print_call(r); // prints "cock-a-doodle-doo!"
std::vector<Animal*> v; // vector of pointers, to allow call to overridden virtual function
v.push_back(new Hen());
v.push_back(new Rooster());
for (auto a : v) std::cout << a->call() << std::endl;
● Using virtual functions allows us to implement dynamic polymorphism, a.k.a. runtime polymorphism.
This means that the implementation of the polymorphic method to be used is known only at runtime.
To support this mechanism, both memory and execution overheads are introduced!
● Most compilers use vptrs and vtables to implement dynamic polymorphism.
– vtable: hidden static member added to each class with virtual functions, with pointers to functions.
– vptr: hidden pointer added to any object of a class with virtual functions, pointing to the correct vtable
→ Space-cost overhead: each object of a class with virtual functions requires an extra member.
sizeof(vptr) = sizeof(void*) could be 8 bytes on a 64-bit machine: a lot for small-size classes!!
The Cost of Dynamic Polymorphism
6
struct X {
int val; // sizeof(int) = 4
double foo(); // function, doesn't take space!
};
sizeof(X) = 4;
struct Y {
int val; // sizeof(int) = 4
virtual double foo(); // virtual function, sizeof(void*) = 8
};
sizeof(Y) = 16; // 4(val) + 8(vptr) + 4(bit padding) !!
→ Time-cost overhead: virtual functions (in most cases) cannot be inlined.
Moreover, two levels of indirection are required when calling a virtual functions:
– get the vtable pointed by the vptr (pointer deference)
– get the method pointed by the vtable (call to function using pointer to function)
...is this always necessary? CRTP to the rescue!
● Using the CRTP we can implement a compile-time alternative to virtual fcns: static polymorphism.
This will remove the memory and time overhead!
Static Polymorphism
7
Dynamic Polymorphism Static Polymorphism
// (Abstract) Base class
struct Animal {
virtual std::string call() = 0; // pure virtual fcn
};
// Derived class
struct Hen: Animal {
virtual std::string call() { return "cluck!"; }
};
void print_call(Animal& a) {
std::cout << a.call() << std::endl;
}
Hen h; print_call(h); // prints "cluck!"
// (Templated) Base class
template <class T> struct Animal {
std::string call() { return static_cast<T*>(this)->call(); }
};
// Derived class (using CRTP!!)
struct Hen: Animal<Hen> {
std::string call() { return "cluck!"; }
};
template <class T> void print_call(Animal<T> & a) {
std::cout << a.call() << std::endl;
}
Hen h; print_call(h); // prints "cluck!"
● Of course, this comes with some limitations in the flexibility of static polymorphism.
E.g. different CRTP-Derived classes cannot be addressed with a common Base pointer/reference!
std::vector<Animal*> vec = {new Hen(), new Frog(), new Hen()}; // only works with dynamic polymorphism!
for (auto x : vec) print_call(*x);
Recap: Static VS Dynamic Polymorphism
8
Dynamic Polymorphism
● resolved at run time (dynamic binding)
using vptr and vtable
● base class is abstract if any of its functions
is a pure virtual (virtual void foo() =0;)
● memory cost to store vptr in each object,
can be significant for small classes
● time cost for dynamic dispatch at every
virtual function call, no inlining
● very flexible: pass base pointer/reference to
a function, iterate over arrays of base
pointers/references, ...
Static Polymorphism
● resolved at compile time (early binding)
using CRTP templates resolution
● base class is a templated class, its methods
call the ones of its derived class instantiation
(static_cast<T*>(this)->call();)
● no memory overhead
● no time overhead, possible inlining for
optimization
● limited flexibility: no addressing via Base
pointers/references
Part 2: Expression Templates
9
Math Expressions: Readability VS Performance
10
● Using C++’s operator overloading and external functions we can implement complex operations
while producing very readable code close to natural language.
Consider, e.g. a class Vec3 and assume we have defined sum and cross product:
Using these functions we can write a code for (a x b) + c that would be totally obfuscated otherwise!
● The second version is way more readable and maintainable. But this has a high performance cost!
→ the first version requires only 1 loop, the second 2 loops (1 fo cross prod., 1 for sum)
→ the first version allocates memory only once, while the second allocates memory
– for the result tmp1 of cross(a, b)
– for the result tmp2 of tmp1 + c
– for the copy constructor of d (unless copy elision and/or move semantics)
● How can we keep readability while avoiding useless loops, memory allocation and copies?
Vec3 cross(Vec3 const& v, Vec3 const& w);
Vec3 Vec3::operator+(Vec3 const& w);
// 1) without operator overloading
Vec3 d;
d[0] = a[1]*b[2] – a[2]*b[1] + c[0];
d[1] = a[2]*b[0] – a[0]*b[2] + c[1];
d[2] = a[0]*b[1] – a[1]*b[0] + c[2];
// 2) with operator overloading !
Vec3 d = cross(a, b) + c;
Expression Templates
11
● The observed performance hit comes from evaluation of expressions before needed.
Expression templates exploit the CRTP to achieve lazy evaluation and loop fusion.
This allows us to produce readable code without any performance loss:
→ the result of an operation between two vectors or expression is an expression
→ an abstract syntax tree of expressions is built at compile time…
→ ...and is evaluated only when needed
c + (a x b) c
ba
x
+
● In practice, expression templates can be implemented as follows.
→ the nodes are templated, generic expression
→ the leaves are actual vectors
→ all the expressions are built at compile-time without evaluation
→ evaluation is triggered by assignment (or copy c-tor) to an actual vector
Vec3 d = c + cross(a, b);
Expression Templates: Example (1/3)
12
● First of all we define the “abstract” base class for a generic vector expression.
Then, the actual vector class inherits through the CRTP and “overloads” the operators.
Remember: the assignment of a vector expression to an actual vector triggers the evaluation!
// Generic vector expression
template <class E>
class VecExpression {
public:
// "virtual" operator[], const version
double operator[](int i) const {
return static_cast<E const&>(*this)[i];
}
// "virtual" size()
size_t size() const {
return static_cast<E const&>(*this).size();
}
// cast to E
E& operator()() {
return static_cast<E&>(*this);
}
E const& operator()() const {
return static_cast<E const&>(*this);
}
};
// Actual vector, inheriting through CRTP
class Vec : public VecExpression<Vec> {
public:
// "overload" operator [], const and non-const versions
double operator[](int i) const { return data_[i]; }
double& operator[](int i) { return data_[i]; }
// "overload" size()
size_t size() const { return data_.size(); }
// c-tor
Vec(size_t sz) : data_(sz) {}
// c-tor from VecExpression, triggers evaluation!
template <class E>
Vec(VecExpression<E> const& ve) : data_(ve.size()) {
for (size_t i =0; i< ve.size(); ++i)
data_[i] = ve[i];
}
private:
std::vector<double> data_;
};
Expression Templates: Example (2/3)
13
● Now we define classes (still inheriting through CRTP) for the operations we want to implement:
let us consider, e.g., sum between vectors and (elementwise) logarithm of a vector.
● Finally, we add two overloads as syntactic sugar.
template <class E1, class E2>
class VecSum: public VecExpression<VecSum<E1, E2> > {
public:
// operator [], const version
double operator[](int i) const { return ve1_[i] + ve2_[i]; }
// size()
size_t size() const {return ve1_.size(); }
// c-tor
VecSum(E1 const& ve1, E2 const& ve2) :
ve1_(ve1), ve2_(ve2)
{
assert(ve1.size()==ve2.size());
}
private:
E1 const& ve1_;
E2 const& ve2_;
};
template <class E>
class VecLog: public VecExpression<VecLog<E> > {
public:
// operator [], const version
double operator[](int i) const { return std::log(ve_[i]); }
// size()
size_t size() const { return ve_.size(); }
// c-tor
VecLog(E const& ve) :
ve_(ve)
{}
private:
E const& ve_;
};
template <class E1, class E2>
VecSum<E1,E2> operator+(E1 const& ve1, E2 const& ve2)
{
return VecSum<E1,E2>(ve1, ve2);
}
template <class E>
VecLog<E> log(E const& ve)
{
return VecLog<E>(ve);
}
Expression Templates: Example (3/3)
14
● We can now use our expression templates to form complex expressions!
Let us now consider the expression of Vec
e = log(a + b + log(c)) + d
If we had used the naive overloadings for operator+ and log the above expression would have
required 5 loops and 5 memory allocations (or even more, without copy elision / move semantics!).
● Using the expression templates that we have implemented, we can avoid all these loops and allocations
while preserving the natural syntax:
● Note that without “syntactic sugar” the syntax would have been cumbersome! Just to write
c = log(a + b)
we would have needed to type
Vec e = log(a + b + log(c)) + d
Vec e = VecLog<VecSum<Vec,Vec> >(VecSum<Vec,Vec>(a,b));
Ad

More Related Content

What's hot (20)

ch7-clean.ppt
ch7-clean.pptch7-clean.ppt
ch7-clean.ppt
RAJULKUMARSUTHAR
 
Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...
Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...
Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...
Complement Verb
 
This pointer
This pointerThis pointer
This pointer
Kamal Acharya
 
Data Types and Structures in R
Data Types and Structures in RData Types and Structures in R
Data Types and Structures in R
Rupak Roy
 
Basic data structures in python
Basic data structures in pythonBasic data structures in python
Basic data structures in python
Celine George
 
Data Analysis with Python Pandas
Data Analysis with Python PandasData Analysis with Python Pandas
Data Analysis with Python Pandas
Neeru Mittal
 
Object Vs Data Structure - Clean code chapter6
Object Vs Data Structure - Clean code chapter6Object Vs Data Structure - Clean code chapter6
Object Vs Data Structure - Clean code chapter6
Maksud Chowdhury
 
Data frame operations
Data frame operationsData frame operations
Data frame operations
19MSS011dhanyatha
 
R Programming: Transform/Reshape Data In R
R Programming: Transform/Reshape Data In RR Programming: Transform/Reshape Data In R
R Programming: Transform/Reshape Data In R
Rsquared Academy
 
Structures
StructuresStructures
Structures
archikabhatia
 
Friends function and_classes
Friends function and_classesFriends function and_classes
Friends function and_classes
asadsardar
 
Structure in c
Structure in cStructure in c
Structure in c
baabtra.com - No. 1 supplier of quality freshers
 
Static and Dynamic polymorphism in C++
Static and Dynamic polymorphism in C++Static and Dynamic polymorphism in C++
Static and Dynamic polymorphism in C++
Anil Bapat
 
Chapter 07 inheritance
Chapter 07 inheritanceChapter 07 inheritance
Chapter 07 inheritance
Praveen M Jigajinni
 
Python: Polymorphism
Python: PolymorphismPython: Polymorphism
Python: Polymorphism
Damian T. Gordon
 
Operator overloading
Operator overloadingOperator overloading
Operator overloading
Burhan Ahmed
 
What is Range Function? | Range in Python Explained | Edureka
What is Range Function? | Range in Python Explained | EdurekaWhat is Range Function? | Range in Python Explained | Edureka
What is Range Function? | Range in Python Explained | Edureka
Edureka!
 
C Programming: Structure and Union
C Programming: Structure and UnionC Programming: Structure and Union
C Programming: Structure and Union
Selvaraj Seerangan
 
Python-List comprehension
Python-List comprehensionPython-List comprehension
Python-List comprehension
Colin Su
 
Stored procedure
Stored procedureStored procedure
Stored procedure
Deepak Sharma
 
Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...
Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...
Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11,...
Complement Verb
 
Data Types and Structures in R
Data Types and Structures in RData Types and Structures in R
Data Types and Structures in R
Rupak Roy
 
Basic data structures in python
Basic data structures in pythonBasic data structures in python
Basic data structures in python
Celine George
 
Data Analysis with Python Pandas
Data Analysis with Python PandasData Analysis with Python Pandas
Data Analysis with Python Pandas
Neeru Mittal
 
Object Vs Data Structure - Clean code chapter6
Object Vs Data Structure - Clean code chapter6Object Vs Data Structure - Clean code chapter6
Object Vs Data Structure - Clean code chapter6
Maksud Chowdhury
 
R Programming: Transform/Reshape Data In R
R Programming: Transform/Reshape Data In RR Programming: Transform/Reshape Data In R
R Programming: Transform/Reshape Data In R
Rsquared Academy
 
Friends function and_classes
Friends function and_classesFriends function and_classes
Friends function and_classes
asadsardar
 
Static and Dynamic polymorphism in C++
Static and Dynamic polymorphism in C++Static and Dynamic polymorphism in C++
Static and Dynamic polymorphism in C++
Anil Bapat
 
Operator overloading
Operator overloadingOperator overloading
Operator overloading
Burhan Ahmed
 
What is Range Function? | Range in Python Explained | Edureka
What is Range Function? | Range in Python Explained | EdurekaWhat is Range Function? | Range in Python Explained | Edureka
What is Range Function? | Range in Python Explained | Edureka
Edureka!
 
C Programming: Structure and Union
C Programming: Structure and UnionC Programming: Structure and Union
C Programming: Structure and Union
Selvaraj Seerangan
 
Python-List comprehension
Python-List comprehensionPython-List comprehension
Python-List comprehension
Colin Su
 

Similar to [C++] The Curiously Recurring Template Pattern: Static Polymorphsim and Expression Templates (20)

Functions And Header Files In C++ | Bjarne stroustrup
Functions And Header Files In C++ | Bjarne stroustrupFunctions And Header Files In C++ | Bjarne stroustrup
Functions And Header Files In C++ | Bjarne stroustrup
SyedHaroonShah4
 
Beauty and Power of Go
Beauty and Power of GoBeauty and Power of Go
Beauty and Power of Go
Frank Müller
 
C++ theory
C++ theoryC++ theory
C++ theory
Shyam Khant
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
Guy Komari
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
LogeekNightUkraine
 
C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)
Saifur Rahman
 
C programming language tutorial
C programming language tutorial C programming language tutorial
C programming language tutorial
javaTpoint s
 
Go Programming Language (Golang)
Go Programming Language (Golang)Go Programming Language (Golang)
Go Programming Language (Golang)
Ishin Vin
 
Scala - brief intro
Scala - brief introScala - brief intro
Scala - brief intro
Razvan Cojocaru
 
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Chris Adamson
 
Summary of C++17 features
Summary of C++17 featuresSummary of C++17 features
Summary of C++17 features
Bartlomiej Filipek
 
C Tutorials
C TutorialsC Tutorials
C Tutorials
Sudharsan S
 
Lecture6.ppt
Lecture6.pptLecture6.ppt
Lecture6.ppt
ammu241754
 
Handling Exceptions In C &amp; C++ [Part B] Ver 2
Handling Exceptions In C &amp; C++ [Part B] Ver 2Handling Exceptions In C &amp; C++ [Part B] Ver 2
Handling Exceptions In C &amp; C++ [Part B] Ver 2
ppd1961
 
Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)
Oky Firmansyah
 
How to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ CodeHow to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ Code
Microsoft Tech Community
 
How to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ CodeHow to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ Code
Microsoft Tech Community
 
C++aptitude questions and answers
C++aptitude questions and answersC++aptitude questions and answers
C++aptitude questions and answers
sheibansari
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in go
borderj
 
ppl unit 3.pptx ppl unit 3 usefull can understood
ppl unit 3.pptx ppl unit 3 usefull can understoodppl unit 3.pptx ppl unit 3 usefull can understood
ppl unit 3.pptx ppl unit 3 usefull can understood
divasivavishnu2003
 
Functions And Header Files In C++ | Bjarne stroustrup
Functions And Header Files In C++ | Bjarne stroustrupFunctions And Header Files In C++ | Bjarne stroustrup
Functions And Header Files In C++ | Bjarne stroustrup
SyedHaroonShah4
 
Beauty and Power of Go
Beauty and Power of GoBeauty and Power of Go
Beauty and Power of Go
Frank Müller
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
Guy Komari
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
LogeekNightUkraine
 
C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)
Saifur Rahman
 
C programming language tutorial
C programming language tutorial C programming language tutorial
C programming language tutorial
javaTpoint s
 
Go Programming Language (Golang)
Go Programming Language (Golang)Go Programming Language (Golang)
Go Programming Language (Golang)
Ishin Vin
 
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Chris Adamson
 
Handling Exceptions In C &amp; C++ [Part B] Ver 2
Handling Exceptions In C &amp; C++ [Part B] Ver 2Handling Exceptions In C &amp; C++ [Part B] Ver 2
Handling Exceptions In C &amp; C++ [Part B] Ver 2
ppd1961
 
Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)
Oky Firmansyah
 
How to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ CodeHow to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ Code
Microsoft Tech Community
 
How to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ CodeHow to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ Code
Microsoft Tech Community
 
C++aptitude questions and answers
C++aptitude questions and answersC++aptitude questions and answers
C++aptitude questions and answers
sheibansari
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in go
borderj
 
ppl unit 3.pptx ppl unit 3 usefull can understood
ppl unit 3.pptx ppl unit 3 usefull can understoodppl unit 3.pptx ppl unit 3 usefull can understood
ppl unit 3.pptx ppl unit 3 usefull can understood
divasivavishnu2003
 
Ad

More from Francesco Casalegno (7)

DVC - Git-like Data Version Control for Machine Learning projects
DVC - Git-like Data Version Control for Machine Learning projectsDVC - Git-like Data Version Control for Machine Learning projects
DVC - Git-like Data Version Control for Machine Learning projects
Francesco Casalegno
 
Ordinal Regression and Machine Learning: Applications, Methods, Metrics
Ordinal Regression and Machine Learning: Applications, Methods, MetricsOrdinal Regression and Machine Learning: Applications, Methods, Metrics
Ordinal Regression and Machine Learning: Applications, Methods, Metrics
Francesco Casalegno
 
Recommender Systems
Recommender SystemsRecommender Systems
Recommender Systems
Francesco Casalegno
 
Markov Chain Monte Carlo Methods
Markov Chain Monte Carlo MethodsMarkov Chain Monte Carlo Methods
Markov Chain Monte Carlo Methods
Francesco Casalegno
 
Hyperparameter Optimization for Machine Learning
Hyperparameter Optimization for Machine LearningHyperparameter Optimization for Machine Learning
Hyperparameter Optimization for Machine Learning
Francesco Casalegno
 
Confidence Intervals––Exact Intervals, Jackknife, and Bootstrap
Confidence Intervals––Exact Intervals, Jackknife, and BootstrapConfidence Intervals––Exact Intervals, Jackknife, and Bootstrap
Confidence Intervals––Exact Intervals, Jackknife, and Bootstrap
Francesco Casalegno
 
Smart Pointers in C++
Smart Pointers in C++Smart Pointers in C++
Smart Pointers in C++
Francesco Casalegno
 
DVC - Git-like Data Version Control for Machine Learning projects
DVC - Git-like Data Version Control for Machine Learning projectsDVC - Git-like Data Version Control for Machine Learning projects
DVC - Git-like Data Version Control for Machine Learning projects
Francesco Casalegno
 
Ordinal Regression and Machine Learning: Applications, Methods, Metrics
Ordinal Regression and Machine Learning: Applications, Methods, MetricsOrdinal Regression and Machine Learning: Applications, Methods, Metrics
Ordinal Regression and Machine Learning: Applications, Methods, Metrics
Francesco Casalegno
 
Markov Chain Monte Carlo Methods
Markov Chain Monte Carlo MethodsMarkov Chain Monte Carlo Methods
Markov Chain Monte Carlo Methods
Francesco Casalegno
 
Hyperparameter Optimization for Machine Learning
Hyperparameter Optimization for Machine LearningHyperparameter Optimization for Machine Learning
Hyperparameter Optimization for Machine Learning
Francesco Casalegno
 
Confidence Intervals––Exact Intervals, Jackknife, and Bootstrap
Confidence Intervals––Exact Intervals, Jackknife, and BootstrapConfidence Intervals––Exact Intervals, Jackknife, and Bootstrap
Confidence Intervals––Exact Intervals, Jackknife, and Bootstrap
Francesco Casalegno
 
Ad

Recently uploaded (20)

Revolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptxRevolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptx
nidhisingh691197
 
The Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdfThe Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdf
drewplanas10
 
Scaling GraphRAG: Efficient Knowledge Retrieval for Enterprise AI
Scaling GraphRAG:  Efficient Knowledge Retrieval for Enterprise AIScaling GraphRAG:  Efficient Knowledge Retrieval for Enterprise AI
Scaling GraphRAG: Efficient Knowledge Retrieval for Enterprise AI
danshalev
 
PDF Reader Pro Crack Latest Version FREE Download 2025
PDF Reader Pro Crack Latest Version FREE Download 2025PDF Reader Pro Crack Latest Version FREE Download 2025
PDF Reader Pro Crack Latest Version FREE Download 2025
mu394968
 
Top 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdfTop 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdf
AffinityCore
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
Lionel Briand
 
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Lionel Briand
 
Landscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature ReviewLandscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature Review
Hironori Washizaki
 
Societal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainabilitySocietal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainability
Jordi Cabot
 
Automation Techniques in RPA - UiPath Certificate
Automation Techniques in RPA - UiPath CertificateAutomation Techniques in RPA - UiPath Certificate
Automation Techniques in RPA - UiPath Certificate
VICTOR MAESTRE RAMIREZ
 
Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025
fs4635986
 
Not So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java WebinarNot So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java Webinar
Tier1 app
 
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
AxisTechnolabs
 
Why Orangescrum Is a Game Changer for Construction Companies in 2025
Why Orangescrum Is a Game Changer for Construction Companies in 2025Why Orangescrum Is a Game Changer for Construction Companies in 2025
Why Orangescrum Is a Game Changer for Construction Companies in 2025
Orangescrum
 
Expand your AI adoption with AgentExchange
Expand your AI adoption with AgentExchangeExpand your AI adoption with AgentExchange
Expand your AI adoption with AgentExchange
Fexle Services Pvt. Ltd.
 
Cryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptxCryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptx
riyageorge2024
 
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Eric D. Schabell
 
How can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptxHow can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptx
laravinson24
 
Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025
mu394968
 
Revolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptxRevolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptx
nidhisingh691197
 
The Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdfThe Significance of Hardware in Information Systems.pdf
The Significance of Hardware in Information Systems.pdf
drewplanas10
 
Scaling GraphRAG: Efficient Knowledge Retrieval for Enterprise AI
Scaling GraphRAG:  Efficient Knowledge Retrieval for Enterprise AIScaling GraphRAG:  Efficient Knowledge Retrieval for Enterprise AI
Scaling GraphRAG: Efficient Knowledge Retrieval for Enterprise AI
danshalev
 
PDF Reader Pro Crack Latest Version FREE Download 2025
PDF Reader Pro Crack Latest Version FREE Download 2025PDF Reader Pro Crack Latest Version FREE Download 2025
PDF Reader Pro Crack Latest Version FREE Download 2025
mu394968
 
Top 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdfTop 10 Data Cleansing Tools for 2025.pdf
Top 10 Data Cleansing Tools for 2025.pdf
AffinityCore
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
FlakyFix: Using Large Language Models for Predicting Flaky Test Fix Categorie...
Lionel Briand
 
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Lionel Briand
 
Landscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature ReviewLandscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature Review
Hironori Washizaki
 
Societal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainabilitySocietal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainability
Jordi Cabot
 
Automation Techniques in RPA - UiPath Certificate
Automation Techniques in RPA - UiPath CertificateAutomation Techniques in RPA - UiPath Certificate
Automation Techniques in RPA - UiPath Certificate
VICTOR MAESTRE RAMIREZ
 
Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025Apple Logic Pro X Crack FRESH Version 2025
Apple Logic Pro X Crack FRESH Version 2025
fs4635986
 
Not So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java WebinarNot So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java Webinar
Tier1 app
 
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
AxisTechnolabs
 
Why Orangescrum Is a Game Changer for Construction Companies in 2025
Why Orangescrum Is a Game Changer for Construction Companies in 2025Why Orangescrum Is a Game Changer for Construction Companies in 2025
Why Orangescrum Is a Game Changer for Construction Companies in 2025
Orangescrum
 
Expand your AI adoption with AgentExchange
Expand your AI adoption with AgentExchangeExpand your AI adoption with AgentExchange
Expand your AI adoption with AgentExchange
Fexle Services Pvt. Ltd.
 
Cryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptxCryptocurrency Exchange Script like Binance.pptx
Cryptocurrency Exchange Script like Binance.pptx
riyageorge2024
 
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Mastering Fluent Bit: Ultimate Guide to Integrating Telemetry Pipelines with ...
Eric D. Schabell
 
How can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptxHow can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptx
laravinson24
 
Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025
mu394968
 

[C++] The Curiously Recurring Template Pattern: Static Polymorphsim and Expression Templates

  • 1. The CRTP: Static Polymorphism and Expression Templates Francesco Casalegno
  • 2. In this presentation... 1. Understand the CRTP (Curiously Recurring Template Pattern) template <class T> class Animal { … }; class Chicken: public Animal<Chicken> { … }; 2. Implement compile-time polymorphism & avoid overhead of virtual functions // run-time polymorphism void call_animal(Animal& a) { std::cout << a.call() << std::endl; } // overhead... // compile-time polymorphism template <class T> void call_animal(Animal<T>& a) { std::cout << a.call() << std::endl; } // no overhead! 3. Implement expression templates & avoid useless loops and copies Vec<double> x(10), y(10), z(10); Vec<double> tot = x + y * z; // how to avoid 2 loops and 2 copies here? 2
  • 3. The Curiously Recurring Template Pattern (CRTP) ● A class template (e.g. std::vector<T>, std::map<T1,T2>, … ) defines a family of classes. ● We can also derive a class X from a class template that uses X itself as template parameter! Does that sound complicated? Easier done than said. This C++ template construct is called the Curiously Recurring Template Pattern (CRTP). ● Why do we need this curious pattern? → static polymorphism: alternative to virtual, avoids memory and execution time overhead → expression templates: computes expressions only when needed, removes loops and copies 3 Container<double> u; // container of doubles Container<char> v; // container of chars Container<Container<int*> > w; // container of containers of int ptrs // Container storing objects of some type T template <class T> class Container { T* data_; // buffer containing the data size_t size_; // buffer's length }; template <class T> class Base { … }; class Derived: Base<Derived> { … }; // A curious derivation!
  • 4. Part 1: Static Polymorphism 4
  • 5. ● The keyword virtual is used to allow a method of a class Base to support dynamic polymorphism. This means that the method can be overridden in a class Derived, such that any call to the virtual function from a Base pointer/reference to a Derived object is resolved as if it came from a Derived: ● Dynamic polymorphism can be very useful in the following cases: → call a method of Derived from an external function → iterate some operation on a vector of pointers to Base Dynamic Polymorphism 5 struct Animal { virtual std::string call() const { return "animal call"; } std::string food() const { return "animal food"; } }; struct Hen: Animal { virtual std::string call() const override { return "cluck!"; } std::string food() const { return "corn"; } }; // Example of usage Hen h; Animal* ptr = &h; ptr->call(); // "cluck!", because call() is an overridden virtual Animal& ref = h; ref.food(); // "animal food", because food() is not virtual // pass by reference (or pointer), to allow call to overridden virtual function void print_call(Animal const& a) { std::cout << a.call() << std::endl; } Hen h; print_call(h); // prints "cluck!" Rooster r; print_call(r); // prints "cock-a-doodle-doo!" std::vector<Animal*> v; // vector of pointers, to allow call to overridden virtual function v.push_back(new Hen()); v.push_back(new Rooster()); for (auto a : v) std::cout << a->call() << std::endl;
  • 6. ● Using virtual functions allows us to implement dynamic polymorphism, a.k.a. runtime polymorphism. This means that the implementation of the polymorphic method to be used is known only at runtime. To support this mechanism, both memory and execution overheads are introduced! ● Most compilers use vptrs and vtables to implement dynamic polymorphism. – vtable: hidden static member added to each class with virtual functions, with pointers to functions. – vptr: hidden pointer added to any object of a class with virtual functions, pointing to the correct vtable → Space-cost overhead: each object of a class with virtual functions requires an extra member. sizeof(vptr) = sizeof(void*) could be 8 bytes on a 64-bit machine: a lot for small-size classes!! The Cost of Dynamic Polymorphism 6 struct X { int val; // sizeof(int) = 4 double foo(); // function, doesn't take space! }; sizeof(X) = 4; struct Y { int val; // sizeof(int) = 4 virtual double foo(); // virtual function, sizeof(void*) = 8 }; sizeof(Y) = 16; // 4(val) + 8(vptr) + 4(bit padding) !! → Time-cost overhead: virtual functions (in most cases) cannot be inlined. Moreover, two levels of indirection are required when calling a virtual functions: – get the vtable pointed by the vptr (pointer deference) – get the method pointed by the vtable (call to function using pointer to function) ...is this always necessary? CRTP to the rescue!
  • 7. ● Using the CRTP we can implement a compile-time alternative to virtual fcns: static polymorphism. This will remove the memory and time overhead! Static Polymorphism 7 Dynamic Polymorphism Static Polymorphism // (Abstract) Base class struct Animal { virtual std::string call() = 0; // pure virtual fcn }; // Derived class struct Hen: Animal { virtual std::string call() { return "cluck!"; } }; void print_call(Animal& a) { std::cout << a.call() << std::endl; } Hen h; print_call(h); // prints "cluck!" // (Templated) Base class template <class T> struct Animal { std::string call() { return static_cast<T*>(this)->call(); } }; // Derived class (using CRTP!!) struct Hen: Animal<Hen> { std::string call() { return "cluck!"; } }; template <class T> void print_call(Animal<T> & a) { std::cout << a.call() << std::endl; } Hen h; print_call(h); // prints "cluck!" ● Of course, this comes with some limitations in the flexibility of static polymorphism. E.g. different CRTP-Derived classes cannot be addressed with a common Base pointer/reference! std::vector<Animal*> vec = {new Hen(), new Frog(), new Hen()}; // only works with dynamic polymorphism! for (auto x : vec) print_call(*x);
  • 8. Recap: Static VS Dynamic Polymorphism 8 Dynamic Polymorphism ● resolved at run time (dynamic binding) using vptr and vtable ● base class is abstract if any of its functions is a pure virtual (virtual void foo() =0;) ● memory cost to store vptr in each object, can be significant for small classes ● time cost for dynamic dispatch at every virtual function call, no inlining ● very flexible: pass base pointer/reference to a function, iterate over arrays of base pointers/references, ... Static Polymorphism ● resolved at compile time (early binding) using CRTP templates resolution ● base class is a templated class, its methods call the ones of its derived class instantiation (static_cast<T*>(this)->call();) ● no memory overhead ● no time overhead, possible inlining for optimization ● limited flexibility: no addressing via Base pointers/references
  • 9. Part 2: Expression Templates 9
  • 10. Math Expressions: Readability VS Performance 10 ● Using C++’s operator overloading and external functions we can implement complex operations while producing very readable code close to natural language. Consider, e.g. a class Vec3 and assume we have defined sum and cross product: Using these functions we can write a code for (a x b) + c that would be totally obfuscated otherwise! ● The second version is way more readable and maintainable. But this has a high performance cost! → the first version requires only 1 loop, the second 2 loops (1 fo cross prod., 1 for sum) → the first version allocates memory only once, while the second allocates memory – for the result tmp1 of cross(a, b) – for the result tmp2 of tmp1 + c – for the copy constructor of d (unless copy elision and/or move semantics) ● How can we keep readability while avoiding useless loops, memory allocation and copies? Vec3 cross(Vec3 const& v, Vec3 const& w); Vec3 Vec3::operator+(Vec3 const& w); // 1) without operator overloading Vec3 d; d[0] = a[1]*b[2] – a[2]*b[1] + c[0]; d[1] = a[2]*b[0] – a[0]*b[2] + c[1]; d[2] = a[0]*b[1] – a[1]*b[0] + c[2]; // 2) with operator overloading ! Vec3 d = cross(a, b) + c;
  • 11. Expression Templates 11 ● The observed performance hit comes from evaluation of expressions before needed. Expression templates exploit the CRTP to achieve lazy evaluation and loop fusion. This allows us to produce readable code without any performance loss: → the result of an operation between two vectors or expression is an expression → an abstract syntax tree of expressions is built at compile time… → ...and is evaluated only when needed c + (a x b) c ba x + ● In practice, expression templates can be implemented as follows. → the nodes are templated, generic expression → the leaves are actual vectors → all the expressions are built at compile-time without evaluation → evaluation is triggered by assignment (or copy c-tor) to an actual vector Vec3 d = c + cross(a, b);
  • 12. Expression Templates: Example (1/3) 12 ● First of all we define the “abstract” base class for a generic vector expression. Then, the actual vector class inherits through the CRTP and “overloads” the operators. Remember: the assignment of a vector expression to an actual vector triggers the evaluation! // Generic vector expression template <class E> class VecExpression { public: // "virtual" operator[], const version double operator[](int i) const { return static_cast<E const&>(*this)[i]; } // "virtual" size() size_t size() const { return static_cast<E const&>(*this).size(); } // cast to E E& operator()() { return static_cast<E&>(*this); } E const& operator()() const { return static_cast<E const&>(*this); } }; // Actual vector, inheriting through CRTP class Vec : public VecExpression<Vec> { public: // "overload" operator [], const and non-const versions double operator[](int i) const { return data_[i]; } double& operator[](int i) { return data_[i]; } // "overload" size() size_t size() const { return data_.size(); } // c-tor Vec(size_t sz) : data_(sz) {} // c-tor from VecExpression, triggers evaluation! template <class E> Vec(VecExpression<E> const& ve) : data_(ve.size()) { for (size_t i =0; i< ve.size(); ++i) data_[i] = ve[i]; } private: std::vector<double> data_; };
  • 13. Expression Templates: Example (2/3) 13 ● Now we define classes (still inheriting through CRTP) for the operations we want to implement: let us consider, e.g., sum between vectors and (elementwise) logarithm of a vector. ● Finally, we add two overloads as syntactic sugar. template <class E1, class E2> class VecSum: public VecExpression<VecSum<E1, E2> > { public: // operator [], const version double operator[](int i) const { return ve1_[i] + ve2_[i]; } // size() size_t size() const {return ve1_.size(); } // c-tor VecSum(E1 const& ve1, E2 const& ve2) : ve1_(ve1), ve2_(ve2) { assert(ve1.size()==ve2.size()); } private: E1 const& ve1_; E2 const& ve2_; }; template <class E> class VecLog: public VecExpression<VecLog<E> > { public: // operator [], const version double operator[](int i) const { return std::log(ve_[i]); } // size() size_t size() const { return ve_.size(); } // c-tor VecLog(E const& ve) : ve_(ve) {} private: E const& ve_; }; template <class E1, class E2> VecSum<E1,E2> operator+(E1 const& ve1, E2 const& ve2) { return VecSum<E1,E2>(ve1, ve2); } template <class E> VecLog<E> log(E const& ve) { return VecLog<E>(ve); }
  • 14. Expression Templates: Example (3/3) 14 ● We can now use our expression templates to form complex expressions! Let us now consider the expression of Vec e = log(a + b + log(c)) + d If we had used the naive overloadings for operator+ and log the above expression would have required 5 loops and 5 memory allocations (or even more, without copy elision / move semantics!). ● Using the expression templates that we have implemented, we can avoid all these loops and allocations while preserving the natural syntax: ● Note that without “syntactic sugar” the syntax would have been cumbersome! Just to write c = log(a + b) we would have needed to type Vec e = log(a + b + log(c)) + d Vec e = VecLog<VecSum<Vec,Vec> >(VecSum<Vec,Vec>(a,b));