Expression templates are typically used in linear algebra and are “structures representing a computation at compile-time, which are evaluated only as needed to produce efficient code for the entire computation” (https://en.wikipedia.org/wiki/Expression_templates). In other words, expression templates are only evaluated when needed.
I provide you with this post only the critical ideas of expression templates. To use them, you should study further content, such as
- C++ Templates: The Complete Guide by David Vandervoorde, Nicolai M. Josuttis, and Douglas Gregor (http://www.tmplbook.com/)
- Boost Basic Linear Algebra Library (https://www.boost.org/doc/libs/1_59_0/libs/numeric/ublas/doc/index.html)
- Expression Templates Revisited by Klaus Iglberger (https://www.youtube.com/watch?v=hfn0BVOegac). Klaus’s talk demystifies many performance-related myths about expression templates.
What problem do expression templates solve? Thanks to expression templates, you can get rid of superfluous temporary objects in expressions. What do I mean by superfluous temporary objects? My implementation of the class MyVector.
A first naive Approach
MyVector is a simple wrapper for a std::vector<T>. The wrapper has two constructors (lines 1 and 2), knows its length (line 3), and supports the reading (line 4) and writing (line 4) by index.
Thanks to the overloaded + operator (line 6), the overloaded * operator (line 7), and the overloaded output operator (line 8) the objects x, y, and result behave like numbers.
Why is this implementation naive? The answer is in the expression result = x + x + y * y. To evaluate the expression, three temporary objects are needed to hold the result of each arithmetic expression.
How can I get rid of the temporaries? The idea is simple. Instead of performing the vector operations greedy, I lazily create the expression tree for
result[i] at compile time. Lazy evaluation means that an expression is only evaluated when needed.
There are no temporaries needed for the expression result[i] = x[i] + x[i] + y[i] * y[i]. The assignment triggers the evaluation. Sadly, the code is, even in this simple usage, not so easy to digest.
The key difference between the first naive implementation and this implementation with expression templates is that the overloaded + and + operators return in the case of the expression tree proxy objects. These proxies represent the expression trees (lines 1 and 2). The expression trees are only created but not evaluated. Lazy, of course. The assignment operator (line 3) triggers the evaluation of the expression tree that needs no temporaries.
The result is the same.
Thanks to the compiler explorer, I can visualize the magic of the program vectorArithmeticExpressionTemplates.cpp.
Under the hood
Here are the essential assembler instructions for the final assignment in the main function:
result= x + x + y * y.
The expression tree in the assembler snippet looks scary, but you can see the structure with a sharp eye. For simplicity reasons, I ignored std::allocator in my graphic.
A policy is a generic function or class whose behavior can be configured. Let me introduce them in my next post.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, and Marco Parri Empoli.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
|My special thanks to Embarcadero|
|My special thanks to PVS-Studio|
|My special thanks to Tipi.build|
|My special thanks to Take Up Code|
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
- Embedded Programmierung mit modernem C++ 12.12.2023 – 14.12.2023 (Präsenzschulung, Termingarantie)
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,