Two Wrong Approaches
Get started with a short motivation for concepts.
We'll cover the following...
Concepts are one of the most impactful features of C++20. Consequently, it is an ideal starting point to present the core language features of C++20.
Prior to C++20, we had two diametrically opposed ways to think about functions or classes: defining them for specific types or defining them for generic types. In the latter case, we call them function templates or class templates. Both approaches have their own set of problems. Let’s discuss them.
Too specific
It’s tedious work to overload a function or reimplement a class for each type. To avoid that burden, type conversion often comes to our rescue. What seems like a rescue is often a curse.
#include <iostream>void needInt(int i) {std::cout << "int: " << i << '\n';}int main() {std::cout << std::boolalpha << '\n';double d{1.234};std::cout << "double: " << d << '\n';needInt(d);std::cout << '\n';bool b{true};std::cout << "bool: " << b << '\n';needInt(b);std::cout << '\n';}
In the first case (line 10), I start with a double
and end with an int
(line 12). In the second case, I start with a bool
(line 16) and also end with an int
(line 18).
The program exemplifies two implicit conversions.
Narrowing conversion
Invoking getInt(int a)
with a double
gives you a narrowing conversion. A narrowing conversion includes a loss in accuracy, which we should avoid.
Integral promotion
But the other way around is also not better. Invoking getInt(int a)
with a bool
promotes the bool
to an int
. Surprised? Many C++ developers don’t know which data type they get when they add two bools
...