I often teach the basics of templates. Templates are special. Therefore, I encounter many misconceptions which cause surprises. Here are a few of them.
My first misconception is presumably apparent for many but not all C++ developers.
Templates of Related Types are not Related
First of all, what does the related type mean? My informal term stands for types that can be implicitly converted. Here is the starting point.
The class template Point stands for a point in an n-dimensional space. The type of the coordinates and the dimension can be adjusted (line 1). The coordinates are stored in a std::vector<T>. When I create two points with the same coordinate type and dimension, I can assign them.
Now the misconception begins. You can assign an int to a double (line 3). Therefore, assigning a Point of ints to the point of doubles should be possible. The C++ compiler is quite specific about line 4. Both class templates are not related and cannot be assigned. They are different types.
The error message gives the first hint. I need an assignment operator that supports the conversion from Point<int, 3> to Point<double, 3>. The class template now has a generic copy assignment operator.
Due to line (1), the copy assignment in line (3) works. Let’s have a closer look at the class template Point:
- Point<T, N>& operator=(const Point<T2, N>& point): The assigned to Point is of type Point<T, N> and accepts only the Point, which has the same dimension, but the type could vary: Point<T2, N>.
- static_assert(std::is_convertible<T2, T>::value, “Cannot convert source type to destination type!”): This expression checks with the help of the function std::is_convertible from the type-traits library, if T2 can be converted to T.
When I use lines (4) and (5), the compilation fails:
Line (3) gives an error because both points have different dimensions. Line (4) triggers the static_assert in the assignment operator because a std::string is not convertible to an int.
I assume the next misconception has more surprise potential.
Methods inherited from Class Templates are per se not available
Let’s start simple.
I implemented a class, Base, and Derived. Derived is public derived from Base and can, therefore, be used in its method callBase (line 2), the method func from class Base. Okay, I have nothing to add to the output of the program.
Making Base a class template changes the behavior.
I assume the compiler error may surprise you.
The line “there are no arguments to ‘func’ that depend on a template parameter, so a declaration of ‘func’ must be available” from the error message gives the first hint. func is a so-called non-dependent name because its name does not depend on the template parameter T. The consequence is that the compiler does not look in the from T dependent base class Base<T>, and there is no name func available outside the class template.
There are three workarounds to extend the name lookup to the dependent base class. The following example uses all three.
- Make the name dependent: The call this->func1 in line 1 is dependent because this is implicit dependent. The name lookup will consider, in this case, all base classes.
- Introduce the name into the current scope: The expression using Base<T>::func2 (line 2) introduces func2 into the current scope.
- Call the name fully qualified: Calling func3 fully qualified (line 3) will break a virtual dispatch and may cause new surprises.
In the end, here is the output of the program.
I have more to write about dependent names in my next post. Sometimes you have to disambiguate dependent names with typename or template. If you see this for the first time, you are probably as surprised as me.
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, and Bhavith C Achar.
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,