<limits> Support
Description
The library provides std::numeric_limits specializations for all safe integer types, for the safe floating-point types f32 and f64, and for the bounded types.
These specializations delegate to the underlying type’s numeric_limits, ensuring consistent behavior with the built-in types.
#include <boost/safe_numbers/limits.hpp>
namespace std {
template <>
struct numeric_limits<boost::safe_numbers::u8>;
template <>
struct numeric_limits<boost::safe_numbers::u16>;
template <>
struct numeric_limits<boost::safe_numbers::u32>;
template <>
struct numeric_limits<boost::safe_numbers::u64>;
template <>
struct numeric_limits<boost::safe_numbers::u128>;
template <>
struct numeric_limits<boost::safe_numbers::f32>;
template <>
struct numeric_limits<boost::safe_numbers::f64>;
} // namespace std
Specialization
Each specialization has the following structure, where T is the safe integer type and basis_type is its underlying integer type:
namespace std {
template <>
struct numeric_limits<T>
{
using basis_type = typename T::basis_type;
// Static member constants
static constexpr bool is_specialized = std::numeric_limits<basis_type>::is_specialized;
static constexpr bool is_signed = std::numeric_limits<basis_type>::is_signed;
static constexpr bool is_integer = std::numeric_limits<basis_type>::is_integer;
static constexpr bool is_exact = std::numeric_limits<basis_type>::is_exact;
static constexpr bool has_infinity = std::numeric_limits<basis_type>::has_infinity;
static constexpr bool has_quiet_NaN = std::numeric_limits<basis_type>::has_quiet_NaN;
static constexpr bool has_signaling_NaN = std::numeric_limits<basis_type>::has_signaling_NaN;
// Deprecated in C++23
static constexpr std::float_denorm_style has_denorm = std::numeric_limits<basis_type>::has_denorm;
static constexpr bool has_denorm_loss = std::numeric_limits<basis_type>::has_denorm_loss;
static constexpr std::float_round_style round_style = std::numeric_limits<basis_type>::round_style;
static constexpr bool is_iec559 = std::numeric_limits<basis_type>::is_iec559;
static constexpr bool is_bounded = std::numeric_limits<basis_type>::is_bounded;
static constexpr bool is_modulo = std::numeric_limits<basis_type>::is_modulo;
static constexpr int digits = std::numeric_limits<basis_type>::digits;
static constexpr int digits10 = std::numeric_limits<basis_type>::digits10;
static constexpr int max_digits10 = std::numeric_limits<basis_type>::max_digits10;
static constexpr int radix = std::numeric_limits<basis_type>::radix;
static constexpr int min_exponent = std::numeric_limits<basis_type>::min_exponent;
static constexpr int min_exponent10 = std::numeric_limits<basis_type>::min_exponent10;
static constexpr int max_exponent = std::numeric_limits<basis_type>::max_exponent;
static constexpr int max_exponent10 = std::numeric_limits<basis_type>::max_exponent10;
static constexpr bool traps = std::numeric_limits<basis_type>::traps;
static constexpr bool tinyness_before = std::numeric_limits<basis_type>::tinyness_before;
// Static member functions
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T min() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T max() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T lowest() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T epsilon() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T round_error() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T infinity() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T quiet_NaN() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T signaling_NaN() noexcept;
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T denorm_min() noexcept;
};
} // namespace std
Member Constants
For unsigned integer types, the following values are consistent across all specializations:
| Member | Value | Description |
|---|---|---|
|
|
Type has a specialization |
|
|
Type is unsigned |
|
|
Type represents integers |
|
|
Type uses exact representations |
|
|
Type cannot represent infinity |
|
|
Type cannot represent quiet NaN |
|
|
Type cannot represent signaling NaN |
|
|
Type does not have denormalized values |
|
|
No denormalization loss |
|
|
Rounding truncates toward zero |
|
|
Not IEC 559 (IEEE 754) compliant |
|
|
Type has finite range |
|
|
Overflow does not wrap (throws instead) |
|
|
Binary representation |
|
|
Not applicable for integers |
|
|
Not applicable for integers |
|
|
Not applicable for integers |
|
|
Not applicable for integers |
|
platform-dependent |
Whether arithmetic traps |
|
|
Not applicable for integers |
Type-Specific Values
| Type | digits |
digits10 |
max_digits10 |
|---|---|---|---|
|
8 |
2 |
3 |
|
16 |
4 |
5 |
|
32 |
9 |
10 |
|
64 |
18 |
20 |
|
128 |
38 |
39 |
Member Functions
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T min() noexcept;
Returns the minimum finite value (always T{0} for unsigned types).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T max() noexcept;
Returns the maximum finite value.
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T lowest() noexcept;
Returns the lowest finite value (same as min() for unsigned types).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T epsilon() noexcept;
Returns T{0} (not meaningful for integer types).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T round_error() noexcept;
Returns T{0} (not meaningful for integer types).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T infinity() noexcept;
Returns T{0} (unsigned integers cannot represent infinity).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T quiet_NaN() noexcept;
Returns T{0} (unsigned integers cannot represent NaN).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T signaling_NaN() noexcept;
Returns T{0} (unsigned integers cannot represent NaN).
BOOST_SAFE_NUMBERS_HOST_DEVICE static constexpr T denorm_min() noexcept;
Returns T{0} (not meaningful for integer types).
Floating-Point Specializations
The specializations for f32 and f64 use the same structure shown above, delegating every member to std::numeric_limits<float> and std::numeric_limits<double> respectively.
Unlike the integer specializations, the floating-point members therefore carry their genuine IEEE 754 meaning: the queries below reflect floating-point properties, and the member functions return real floating-point values rather than T{0}.
| Member | f32 and f64 value |
Description |
|---|---|---|
|
|
Floating-point types are signed |
|
|
Type does not represent integers |
|
|
Type uses an approximate representation |
|
|
Type can represent positive and negative infinity |
|
|
Type can represent a quiet NaN |
|
|
Type can represent a signaling NaN |
|
|
Type conforms to IEC 559 (IEEE 754) |
|
|
Type has a finite set of representable values |
|
|
Arithmetic does not wrap |
|
|
Default IEEE 754 rounding |
|
|
Binary representation |
The type-specific values match the underlying float and double:
| Type | digits |
digits10 |
max_digits10 |
min_exponent |
max_exponent |
min_exponent10 |
max_exponent10 |
|---|---|---|---|---|---|---|---|
|
24 |
6 |
9 |
-125 |
128 |
-37 |
38 |
|
53 |
15 |
17 |
-1021 |
1024 |
-307 |
308 |
For these types the member functions return meaningful floating-point values wrapped in the safe type:
| Function | Returns |
|---|---|
|
The smallest positive normal value |
|
The largest finite value |
|
The most negative finite value ( |
|
The difference between |
|
The maximum rounding error ( |
|
Positive infinity |
|
A quiet NaN |
|
A signaling NaN |
|
The smallest positive subnormal value |
infinity(), quiet_NaN(), and signaling_NaN() construct a non-finite f32 or f64. Construction does not validate the value (see Floating-Point Types), so these values are produced without throwing; an exception is only raised when such a value is later observed by a checked arithmetic or <cmath> operation.
|
Bounded Integer Specialization
A partial specialization of std::numeric_limits is provided for all bounded_uint<Min, Max> types.
Static member constants delegate to the underlying hardware type’s std::numeric_limits specialization, just as they do for the safe unsigned integer types.
The key difference is in the min() and max() member functions: rather than returning the hardware type’s full range, they return the compile-time bounds Min and Max.
namespace std {
template <auto Min, auto Max>
class numeric_limits<boost::safe_numbers::bounded_uint<Min, Max>>
{
// Static member constants delegate to std::numeric_limits<underlying_type>
// ...
// Returns bounded_uint constructed from Min
static constexpr bounded_uint<Min, Max> min();
// Returns bounded_uint constructed from Max
static constexpr bounded_uint<Min, Max> max();
// Same as min() for unsigned types
static constexpr bounded_uint<Min, Max> lowest();
// Not meaningful for integer types; returns min()
static constexpr bounded_uint<Min, Max> epsilon();
static constexpr bounded_uint<Min, Max> round_error();
static constexpr bounded_uint<Min, Max> infinity();
static constexpr bounded_uint<Min, Max> quiet_NaN();
static constexpr bounded_uint<Min, Max> signaling_NaN();
static constexpr bounded_uint<Min, Max> denorm_min();
};
} // namespace std
The non-applicable member functions (epsilon, round_error, infinity, quiet_NaN, signaling_NaN, denorm_min) return min() rather than a zero-constructed value, since zero may fall outside the valid range for types with a non-zero lower bound.
|
Example
std::numeric_limits with bounded integer types.// Copyright 2026 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/safe_numbers/bounded_integers.hpp>
#include <boost/safe_numbers/limits.hpp>
#include <boost/safe_numbers/iostream.hpp>
#include <iostream>
#include <limits>
int main()
{
using boost::safe_numbers::bounded_uint;
using percent = bounded_uint<0u, 100u>;
std::cout << "percent type:" << std::endl;
std::cout << " min: " << std::numeric_limits<percent>::min() << std::endl;
std::cout << " max: " << std::numeric_limits<percent>::max() << std::endl;
std::cout << " lowest: " << std::numeric_limits<percent>::lowest() << std::endl;
std::cout << " digits: " << std::numeric_limits<percent>::digits << std::endl;
std::cout << std::endl;
using port = bounded_uint<1u, 65535u>;
std::cout << "port type:" << std::endl;
std::cout << " min: " << std::numeric_limits<port>::min() << std::endl;
std::cout << " max: " << std::numeric_limits<port>::max() << std::endl;
std::cout << " lowest: " << std::numeric_limits<port>::lowest() << std::endl;
std::cout << " digits: " << std::numeric_limits<port>::digits << std::endl;
return 0;
}
Output:
percent type: min: 0 max: 100 lowest: 0 digits: 8 port type: min: 1 max: 65535 lowest: 1 digits: 16
Bounded Floating-Point Specialization
A partial specialization of std::numeric_limits is also provided for bounded_float<Min, Max> on platforms where the bounded floating-point type is available.
It mirrors the bounded integer specialization: the min() and max() member functions return the compile-time bounds Min and Max rather than the underlying type’s full range.
See Bounded Floating-Point Types.
Because a bounded value is a constrained subset of the underlying float or double, several queries differ from the unbounded floating-point specializations:
| Member | Value | Description |
|---|---|---|
|
|
Type does not represent integers |
|
|
Type uses an approximate representation |
|
|
A bounded value cannot be infinite |
|
|
A bounded value cannot be NaN |
|
|
A bounded value cannot be NaN |
|
|
The constrained range is not a full IEC 559 type |
|
|
Type has a finite range |
|
|
Arithmetic does not wrap |
namespace std {
template <auto Min, auto Max>
class numeric_limits<boost::safe_numbers::bounded_float<Min, Max>>
{
// Static member constants delegate to std::numeric_limits<underlying_type>,
// except for the queries listed above
// Returns bounded_float constructed from Min
static constexpr bounded_float<Min, Max> min();
// Returns bounded_float constructed from Max
static constexpr bounded_float<Min, Max> max();
// Same as min()
static constexpr bounded_float<Min, Max> lowest();
// Not meaningful for a bounded range; each returns min()
static constexpr bounded_float<Min, Max> epsilon();
static constexpr bounded_float<Min, Max> round_error();
static constexpr bounded_float<Min, Max> infinity();
static constexpr bounded_float<Min, Max> quiet_NaN();
static constexpr bounded_float<Min, Max> signaling_NaN();
static constexpr bounded_float<Min, Max> denorm_min();
};
} // namespace std
As with the bounded integer specialization, the non-applicable member functions (epsilon, round_error, infinity, quiet_NaN, signaling_NaN, denorm_min) return min() rather than a zero-constructed value, since zero may fall outside the valid range.
|