<type_traits> lets templates ask questions about types at compile time; if constexpr (C++17) keeps only the branch that applies, so each instantiation compiles just the code it needs.
Asking questions about types
#include <iostream>
#include <string>
#include <type_traits>
int main() {
std::cout << std::boolalpha
<< std::is_integral_v<int> << ' '
<< std::is_floating_point_v<int> << ' '
<< std::is_pointer_v<char*> << ' '
<< std::is_same_v<std::remove_const_t<const int>, int> << ' '
<< std::is_trivially_copyable_v<std::string> << ' '
<< std::is_base_of_v<std::exception, std::runtime_error> << '\n';
static_assert(std::is_same_v<std::decay_t<const int&>, int>);
static_assert(sizeof(long long) == 8, "this code assumes 64-bit long long");
}true false true true false true| Trait | Question / transformation |
|---|---|
is_integral_v<T>, is_floating_point_v<T>, is_arithmetic_v<T> | Category checks |
is_same_v<A, B> | Exactly the same type? |
is_base_of_v<B, D>, is_convertible_v<From, To> | Relationships |
remove_reference_t<T>, remove_const_t<T>, decay_t<T> | Strip qualifiers (decay = what pass-by-value does) |
conditional_t<Cond, A, B> | Compile-time ternary on types |
enable_if_t<Cond, T> | Remove an overload unless Cond (pre-C++20 SFINAE) |
if constexpr
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
template <typename T>
std::string describe(const T& value) {
if constexpr (std::is_integral_v<T>)
return "integer " + std::to_string(value * 2); // only compiled for integers
else if constexpr (std::is_floating_point_v<T>)
return "float " + std::to_string(value);
else if constexpr (requires { value.size(); }) // C++20 requires-expression
return "sized thing of " + std::to_string(value.size());
else
return "something else";
}
int main() {
std::cout << describe(21) << '\n' << describe(0.5) << '\n'
<< describe(std::vector<int>{1, 2, 3}) << '\n' << describe(nullptr) << '\n';
}integer 42
float 0.500000
sized thing of 3
something elseWriting your own trait
#include <iostream>
#include <list>
#include <type_traits>
#include <vector>
template <typename T> struct is_vector : std::false_type {};
template <typename T, typename A> struct is_vector<std::vector<T, A>> : std::true_type {};
template <typename T> inline constexpr bool is_vector_v = is_vector<T>::value;
int main() {
std::cout << is_vector_v<std::vector<int>> << is_vector_v<std::list<int>> << is_vector_v<int> << '\n';
}100What is SFINAE?