<type_traits>
The <type_traits>
header is a powerful component of the C++ Standard Library that provides a set of type traits. These are template classes and functions that give information about types at compile-time. This header is crucial for template metaprogramming, enabling compile-time decision making and optimization based on type properties.
value
member#include <iostream>
#include <type_traits>
template <typename T>
void printTypeInfo() {
std::cout << "Is integral? " << std::is_integral<T>::value << std::endl;
std::cout << "Is floating point? " << std::is_floating_point<T>::value << std::endl;
std::cout << "Is pointer? " << std::is_pointer<T>::value << std::endl;
std::cout << "Is const? " << std::is_const<T>::value << std::endl;
}
int main() {
std::cout << "int:" << std::endl;
printTypeInfo<int>();
std::cout << "\ndouble:" << std::endl;
printTypeInfo<double>();
std::cout << "\nint*:" << std::endl;
printTypeInfo<int*>();
std::cout << "\nconst char:" << std::endl;
printTypeInfo<const char>();
return 0;
}
is_integral
, is_floating_point
, is_pointer
, and is_const
.::value
member gives a boolean result indicating whether the type has the queried property.#include <iostream>
#include <type_traits>
template <typename T>
void printModifiedTypeInfo() {
using RemoveConst = typename std::remove_const<T>::type;
using AddPointer = typename std::add_pointer<T>::type;
using RemovePointer = typename std::remove_pointer<T>::type;
std::cout << "Original type is const? " << std::is_const<T>::value << std::endl;
std::cout << "After remove_const is const? " << std::is_const<RemoveConst>::value << std::endl;
std::cout << "After add_pointer is pointer? " << std::is_pointer<AddPointer>::value << std::endl;
std::cout << "After remove_pointer is pointer? " << std::is_pointer<RemovePointer>::value << std::endl;
}
int main() {
std::cout << "const int:" << std::endl;
printModifiedTypeInfo<const int>();
std::cout << "\nint*:" << std::endl;
printModifiedTypeInfo<int*>();
return 0;
}
remove_const
, add_pointer
, and remove_pointer
.typename
keyword is used to specify that the nested ::type
is a type and not a static member.enable_if
#include <iostream>
#include <type_traits>
// Function for integral types
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
isEven(T value) {
return value % 2 == 0;
}
// Function for floating-point types
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
isEven(T value) {
return static_cast<int>(value) % 2 == 0;
}
int main() {
std::cout << "Is 4 even? " << isEven(4) << std::endl;
std::cout << "Is 5 even? " << isEven(5) << std::endl;
std::cout << "Is 3.14 even? " << isEven(3.14) << std::endl;
std::cout << "Is 4.0 even? " << isEven(4.0) << std::endl;
// This would cause a compilation error:
// isEven("not a number");
return 0;
}
std::enable_if
is used to conditionally compile function templates based on type traits.isEven
: one for integral types and one for floating-point types.isEven
with a non-numeric type would result in a compilation error.#include <iostream>
#include <type_traits>
class Base {};
class Derived : public Base {};
class Unrelated {};
// Custom type trait
template <typename T>
struct is_small_type : std::integral_constant<bool, sizeof(T) <= sizeof(void*)> {};
template <typename T>
void printRelationships() {
std::cout << "Is same as Base? " << std::is_same<T, Base>::value << std::endl;
std::cout << "Is base of Derived? " << std::is_base_of<T, Derived>::value << std::endl;
std::cout << "Is derived from Base? " << std::is_base_of<Base, T>::value << std::endl;
std::cout << "Is small type? " << is_small_type<T>::value << std::endl;
}
int main() {
std::cout << "Base:" << std::endl;
printRelationships<Base>();
std::cout << "\nDerived:" << std::endl;
printRelationships<Derived>();
std::cout << "\nUnrelated:" << std::endl;
printRelationships<Unrelated>();
std::cout << "\nint:" << std::endl;
printRelationships<int>();
return 0;
}
is_same
and is_base_of
to check type relationships.is_small_type
is defined to demonstrate how to create user-defined traits.std::integral_constant
is used as a base for our custom trait, following the standard library pattern.#include <iostream>
#include <type_traits>
template <typename T>
class SafeIntegerContainer {
static_assert(std::is_integral<T>::value, "SafeIntegerContainer can only be used with integral types");
public:
void add(T value) {
// Implementation...
}
};
template <bool IsFloatingPoint, typename T>
struct NumberTraits {
using AbsoluteType = typename std::conditional<IsFloatingPoint,
long double,
typename std::conditional<sizeof(T) <= sizeof(int),
int,
long long>::type>::type;
};
template <typename T>
typename NumberTraits<std::is_floating_point<T>::value, T>::AbsoluteType
getAbsoluteValue(T value) {
return std::abs(value);
}
int main() {
SafeIntegerContainer<int> intContainer;
intContainer.add(5);
// This would cause a compilation error:
// SafeIntegerContainer<double> doubleContainer;
std::cout << "Absolute value of -5: " << getAbsoluteValue(-5) << std::endl;
std::cout << "Absolute value of -5.5: " << getAbsoluteValue(-5.5) << std::endl;
return 0;
}
static_assert
is used with type traits to provide compile-time checks.std::conditional
is used to select types based on compile-time conditions.Compiler Support: While most type traits are widely supported, some newer traits might not be available in older compilers.
Performance: Type traits are resolved at compile-time and generally have no runtime cost.
C++17 and Beyond: C++17 introduced _v
suffixed aliases for type traits (e.g., std::is_integral_v<T>
) for more concise usage.
Custom Type Traits: You can create your own type traits following the patterns established in the standard library.
SFINAE: Many type traits are useful in conjunction with SFINAE (Substitution Failure Is Not An Error) for template specialization.
The <type_traits>
header in C++ provides a powerful set of tools for template metaprogramming and type manipulation:
is_integral
, is_class
).is_const
, is_volatile
).remove_const
, add_pointer
).is_same
, is_base_of
).conditional
and enable_if
.These type traits are fundamental to modern C++ template metaprogramming, enabling developers to write more generic and efficient code. They allow for compile-time decision making, type-based optimizations, and safer template code.
By leveraging <type_traits>
, C++ programmers can create more flexible and robust template libraries, implement compile-time optimizations, and write code that adapts to different types while maintaining type safety. This header is an essential tool for advanced C++ programming, particularly in template-heavy codebases and when writing generic libraries.