Concepts and Type Traits
Concepts and Type Traits
Write clearer generic code with explicit constraints and standard type queries.
Concepts and Type Traits
Write clearer generic code with explicit constraints and standard type queries.
Traditional templates often fail with long error messages far from the call site. Concepts let you declare what a type must support.
template <typename T>
concept Printable = requires(T value) {
std::cout << value;
};
template <Printable T>
void print_line(const T& value) {
std::cout << value << '\n';
}
This is easier to read than layers of enable_if.
template <typename T>
concept SmallIntegral = std::integral<T> && (sizeof(T) <= 4);
Compose constraints when the combined name communicates intent better than raw expressions.
template <typename T>
concept ReservableRange = requires(T container, std::size_t n) {
container.reserve(n);
container.begin();
container.end();
};
template <ReservableRange T>
void preallocate_like(T& container, std::size_t count) {
container.reserve(count);
}
This kind of constraint documents API expectations directly instead of burying them in template instantiation failures.
std::is_same_v<T, U>std::is_integral_v<T>std::is_invocable_v<F, Args...>std::remove_cvref_t<T>std::conditional_t<cond, A, B>if constexprtemplate <typename T>
void describe(const T& value) {
if constexpr (std::integral<T>) {
std::cout << "integral\n";
} else {
std::cout << "non-integral\n";
}
}
Use it when one generic implementation needs a few type-specific branches.
template <typename T>
using value_type_t = typename std::remove_cvref_t<T>::value_type;
Traits are often most useful when they clean up dependent names or normalize incoming template arguments.
size() and empty().std::integral and another to std::floating_point.enable_if helper in old code with a named concept.