Type-Traits (Correctness and Optimization)
In this lesson, we'll study type-traits correctness and their optimization using a gcd (greatest common divisor) algorithm along with fill and equal (type-trait features).
Correctness
The reason we use type-traits is correctness and optimization. Let’s start with correctness. The idea is to implement generic gcd algorithms, step by step, to make it more type-safe with the help of the type-traits library.
gcd - The First
Our starting point is the euclid algorithm to calculate the greatest common divisor of two numbers.
It’s quite easy to implement the algorithm as a function template and feed it with various arguments. Let’s start!
#include <iostream>template<typename T>T gcd(T a, T b){if( b == 0 ) return a;else return gcd(b, a % b);}int main(){std::cout << gcd(100, 10) << std::endl; // 10std::cout << gcd(100, 33) << std::endl; // 1std::cout << gcd(100, 0) << std::endl; // 100std::cout << gcd(3.5, 4.0) << std::endl; // ERRORstd::cout << gcd("100", "10") << std::endl; // ERRORstd::cout << gcd(100, 10L) << std::endl; // ERROR}
The function template has two serious issues.
- First, it is too generic. The function template accepts doubles (line 13) and C strings (line 14). But it makes no sense to determine the greatest common divisor of both data types. The modulo operation (
%
) for the double and the C string values fails in line 6. But that’s not the only issue. - Second, gcds depend on one type parameter,
T
. This shows the function template signaturegcd(T a, T b))
.a
andb
have to be of the same typeT
. There is no conversion for type parameters. Therefore, the instantiation of gcd with an int type and a long type (line 15) fails.
gcd - The Second
We can ignore the rest of the examples below where both arguments have to be positive numbers. The static_assert
operator and the predicate std::is_integral<T>::value
will help us to check at compile-time whether T
is an integral type. A predicate always returns a boolean value.
#include <iostream>#include <type_traits>template<typename T>T gcd(T a, T b){static_assert(std::is_integral<T>::value, "T should be integral type!");if( b == 0 ) return a;else return gcd(b, a % b);}int main(){std::cout << gcd(3.5, 4.0) << std::endl;std::cout << gcd("100", "10") << std::endl;}
Great. We have solved the first issue of the gcd algorithm. The compilation will not fail by accident because the modulo operator is not defined for a double value and a C string. The compilation fails because the assertion in line 6 will not hold true. The subtle difference is that we now get an exact error message and not a cryptic output of a failed template instantiation as in the ...