C++ Traits
Introduction
C++ traits is a special case of template programming which usually only focus on type specific features, such as static attributes and static functions. It is one of the most fundamental building blocks for C++ template programming.
In this blog post, I would like to quickly discuss what C++ traits is and how it contributes to C++ template programming.
C++ Traits
C++ traits can be used for unifying the low-level function interface for different types, making the high-level template programming simpler.
For example, if we want to create functions, say greater_than_half_maximum
, for different numerical types, including int32_t
, int64_t
, float
, double
, that use the maximum value of the type, without using traits, we can hardly take the advantage of template programming.
1 |
|
From the above example, we could see that even if we wanted to use template programming, without using traits, the specialization implementations for different types is inevitable.
std::numeric_limits
is a type trait from the C++ standard library which defines the maximum value for different built-in types. By using std::numeric_limits<T>::max()
, we don’t need to create specializations for different types for our particular use case.
1 |
|
For custom numerical types, such as NVIDIA __half
, we could create specializations for std::numeric_limits
instead of for greater_than_half_maximum
.
1 |
|
Of course, one could argue that for $n$ different types, we would have to create $n$ different type traits which is also a lot of work. However, because usually the low-level type traits are more reusable than the high-level specializations, it is more valuable to spend effort on creating low-level type traits than high-level template specializations. In addition, because high-level template specialization usually requires more lines of implementation than type traits, it takes less effort on creating low-level type traits than high-level template specializations.
C++ Traits Contributing to Template Metaprogramming
C++ type traits are critical for template metaprogramming. We will see how it is used for both function template metaprogramming and class template metaprogramming.
Function Template Metaprogramming
When the type traits were used with std::enable_if
, we could specialize the function implementation details for different types, as described in my previous blog post “C++ Template Specialization Using Enable If”.
Class Template Metaprogramming
When the type traits were used with std::conditional_t
, we could specialize the class implementation details for classes that have different types of member variables that cannot be simply templated.
For example, the C++ <random>
library has two functions for generating random numbers from a uniform distribution, including the std::uniform_int_distribution
for generating integer values and std::uniform_real_distribution
for generating real values.
The following implementation unified the two random number generation functions, std::uniform_int_distribution
and std::uniform_real_distribution
, using type trait std::is_integral<T>::value
.
1 |
|
1 | $ g++ random_number_generator.cpp -o random_number_generator -std=c++14 |