There is, in particular, one rule left to template interfaces which are quite interesting: T.47: Avoid highly visible unconstrained templates with common names. Admittedly, the rule T47 is often the reason for unexpected behavior because the wrong function is called.
Although I write today mainly about rule T.47, I have more to say.
- T.47: Avoid highly visible unconstrained templates with common names
- T.48: If your compiler does not support concepts, fake them with
- T.49: Where possible, avoid type-erasure
The get to the point of rule T.47, I have to make a short detour. This detour is about argument-dependent lookup (ADL) also known as Koenig lookup named after Andrew Koenig. First of all. What is an argument-dependent lookup?
Argument-Dependent Lookup (ADL)
Here is the definition of ADL:
- Argument-dependent lookup is a set of rules for looking up unqualified function names. Unqualified function names are additionally looked up in the namespace of their arguments.
Unqualified function names mean functions without the
Fine. Let me remove the syntactic sugar of operator overloading and use the function call directly.
This equivalent program shows what is happening under the hood. The function operator<< is called with the arguments std::cout and a C-string “Argument-dependent lookup”.
Fine? No? The question arises: Where is the definition of the function operator<<. Of course, there is no definition in the global namespace. operator<< is an unqualified function name; therefore, argument-dependent lookup kicks in. The function name is additionally looked up in the namespace of their arguments. In this particular case, the namespace std is due to the first argument std::cout considered, and the lookup finds the appropriate candidate: std::operator<<(std::ostream&, const char*). Often ADL provides you precisely with the function you are looking for, but sometimes…
Now, it is the right time to write about rule T.47:
In the expression std::cout << “Argument-dependent lookup”, the overloaded output operator << is the obvious common name because it is defined in the namespace std. The following program, based on the program of the core guidelines, shows the crucial point of this rule.
I expect that in both cases (2 and 3), the overloaded operator == in Line (4) is called because it takes an argument of type Bad::Number (1); therefore, I should get two times true.
What happened here? The call in line (3) is resolved by the generic equality operator in line (5)? The reason for my surprise is that vec.size() returns a value of type std::size_type, which is an unsigned integer type. This means the equality operator requires a conversation to int
in line (4). This is unnecessary for the generic equality in line (5) because this is a fit without conversion. Thanks to argument-dependent lookup, the generic equality operator belongs to the set of possible overloads.
The rule states “Avoid highly visible unconstrained templates with common names”. Let me see what would happen if I followed the rule and disable the generic equality operator. Here is the fixed code.
Now, the result matches my expectations.
Here are my remarks on the last two rules for template interfaces.
When I present std::enable_if in my seminars, a few participants are slightly scared. Here is the simplified version of a generic greatest common divisor algorithm.
The algorithm is way too generic. It should only work for integral types. Now, std::enable_if from the type-traits library in line (1) comes to my rescue.
The expression std::is_integral (line 2) is critical for understanding the program. This line determines whether the type parameter T is integral. If T is not integral and, therefore, the return value false, there will be no template instantiations for this specific type.
Only if std::is_integral returns true std::enable_if has a public member typedef type. Suppose line (1) is not valid. But this is not an error.
The C++ standard says: When substituting the deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error. There is a shorter acronym for this rule SFINAE (Substitution Failure Is Not An Error).
The compilation output (enable_if.cpp: 20:49) shows it. There is no template specialization for the type double available.
But the output shows more. (enable_if.cpp:7:71): “no named `type* in struct std::enable_if<false, double>“.
Strange, I wrote two posts to type-erasure (C++ Core Guidelines: Type Erasure and C++ Core Guidelines: Type Erasure with Templates) and explained this quite challenging technique. Now, I should avoid it, when possible.
With my next post, I jump from the interfaces of templates to their definition.
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,