Verified Integer Types
Description
The library provides verified integer types that guarantee compile-time validation via consteval constructors and arithmetic.
All values must be known at compile time — at runtime, verified types are read-only constants.
They wrap any library_type (both u8-u128 and bounded_uint), adding a layer of compile-time-only enforcement on top of the existing safety guarantees.
| Type | Basis Type | Underlying Type |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
smallest unsigned type fitting |
Each type exposes an underlying_type member type alias that refers to the underlying fundamental integer type.
#include <boost/safe_numbers/verified_integers.hpp>
namespace boost::safe_numbers {
using verified_u8 = detail::verified_type_basis<u8>;
using verified_u16 = detail::verified_type_basis<u16>;
using verified_u32 = detail::verified_type_basis<u32>;
using verified_u64 = detail::verified_type_basis<u64>;
using verified_u128 = detail::verified_type_basis<u128>;
template <auto Min, auto Max>
using verified_bounded_integer = detail::verified_type_basis<bounded_uint<Min, Max>>;
template <library_type BasisType>
class verified_type_basis {
public:
using underlying_type = underlying_type_t<BasisType>;
// Construction (consteval -- compile-time only)
explicit consteval verified_type_basis(const BasisType basis);
explicit consteval verified_type_basis(const underlying_type val);
// Conversion to basis type and underlying type (constexpr -- works at runtime)
explicit constexpr operator BasisType() const noexcept;
explicit constexpr operator underlying_type() const noexcept;
// Comparison operators (constexpr -- works at runtime)
friend constexpr auto operator<=>(verified_type_basis lhs, verified_type_basis rhs) noexcept
-> std::strong_ordering = default;
// Compound assignment operators (consteval -- compile-time only)
consteval auto operator+=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator-=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator*=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator/=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator%=(verified_type_basis rhs) -> verified_type_basis&;
// Increment and decrement operators (consteval -- compile-time only)
consteval auto operator++() -> verified_type_basis&;
consteval auto operator++(int) -> verified_type_basis;
consteval auto operator--() -> verified_type_basis&;
consteval auto operator--(int) -> verified_type_basis;
}; // class verified_type_basis
// Arithmetic operators (consteval -- compile-time only, overflow = compile error)
template <library_type BasisType>
consteval auto operator+(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator-(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator*(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator/(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator%(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
} // namespace boost::safe_numbers
Operator Behavior
Construction
explicit consteval verified_type_basis(const BasisType basis);
explicit consteval verified_type_basis(const underlying_type val);
Construction is consteval — it can only occur at compile time.
The first overload accepts the safe integer basis type directly; the second accepts the underlying fundamental type and constructs the basis type internally.
If the value is out of range (e.g., for a bounded type), the compilation fails.
Conversion
explicit constexpr operator BasisType() const noexcept;
explicit constexpr operator underlying_type() const noexcept;
Conversion to the basis type or the underlying fundamental type is constexpr and explicit.
These work at runtime, allowing verified values to be used in runtime contexts such as stream output, to_chars, and comparisons.
Comparison Operators
friend constexpr auto operator<=>(verified_type_basis lhs, verified_type_basis rhs) noexcept
-> std::strong_ordering = default;
Full three-way comparison is supported via operator<=>, which returns std::strong_ordering.
All comparison operators (<, ⇐, >, >=, ==, !=) are available.
Comparisons are constexpr and work at runtime.
Arithmetic Operators
template <library_type BasisType>
consteval auto operator+(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator-(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator*(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator/(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
template <library_type BasisType>
consteval auto operator%(const verified_type_basis<BasisType> lhs,
const verified_type_basis<BasisType> rhs) -> verified_type_basis<BasisType>;
All arithmetic operators are consteval — they can only be evaluated at compile time.
The operations delegate to the underlying basis type’s operators, which perform overflow/underflow checking.
If an overflow, underflow, or division-by-zero would occur, the compilation fails with a compiler error.
Compound Assignment Operators
consteval auto operator+=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator-=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator*=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator/=(verified_type_basis rhs) -> verified_type_basis&;
consteval auto operator%=(verified_type_basis rhs) -> verified_type_basis&;
Compound assignment operators are consteval and delegate to the corresponding arithmetic operators.
Overflow at compile time produces a compiler error.
Increment and Decrement Operators
consteval auto operator++() -> verified_type_basis&;
consteval auto operator++(int) -> verified_type_basis;
consteval auto operator--() -> verified_type_basis&;
consteval auto operator--(int) -> verified_type_basis;
-
++(pre/post):consteval. Produces a compile error if the value is already at the maximum. -
--(pre/post):consteval. Produces a compile error if the value is already at the minimum (zero for unbounded types,Minfor bounded types).
Compile-Time vs Runtime
| Operation | Qualifier | Compile-Time | Runtime |
|---|---|---|---|
Construction |
|
Yes |
No |
Arithmetic ( |
|
Yes |
No |
Compound assignment ( |
|
Yes |
No |
Increment/decrement ( |
|
Yes |
No |
Conversion to |
|
Yes |
Yes |
Comparison ( |
|
Yes |
Yes |
Mixed-type arithmetic (verified op basis) |
|
Yes |
Yes |
Mixed-type comparison (verified vs basis) |
|
Yes |
Yes |
Mixed-type bitwise (verified op basis) |
|
Yes |
Yes |
Mixed-Type Operations
Verified types can participate in runtime expressions when combined with their basis types. The result is always the runtime (basis) type, effectively treating the verified value as a read-only constant operand.
Arithmetic
// verified op basis -> basis
template <library_type VerifiedBasisType>
constexpr auto operator+(const verified_type_basis<VerifiedBasisType> lhs,
const VerifiedBasisType rhs) -> VerifiedBasisType;
// basis op verified -> basis
template <library_type VerifiedBasisType>
constexpr auto operator+(const VerifiedBasisType lhs,
const verified_type_basis<VerifiedBasisType> rhs) -> VerifiedBasisType;
All five arithmetic operators (+, -, *, /, %) are supported in both directions.
Cross-width operations (e.g., verified_u32 + u64) are allowed and follow the same rules as the basis types.
Comparisons
template <library_type VerifiedBasisType>
constexpr auto operator<=>(const verified_type_basis<VerifiedBasisType> lhs,
const VerifiedBasisType rhs) -> std::strong_ordering;
template <library_type VerifiedBasisType>
constexpr auto operator==(const verified_type_basis<VerifiedBasisType> lhs,
const VerifiedBasisType rhs) -> bool;
Full three-way and equality comparisons are supported in both directions (verified vs basis, basis vs verified).
Bitwise Operations
template <non_bounded_unsigned_library_type VerifiedBasisType>
constexpr auto operator&(const verified_type_basis<VerifiedBasisType> lhs,
const VerifiedBasisType rhs) -> VerifiedBasisType;
Bitwise operators (&, |, ^, <<, >>) are supported for non-bounded unsigned types in both directions.
Shift operators include overflow checking via throw_exception policy.
Type Safety
Mixed operations between verified types with different basis types produce clear static_assert errors:
constexpr auto a = verified_u32{u32{10}};
constexpr auto b = verified_u64{u64{20}};
auto c = a + b; // error: "Can not perform addition between verified types with different basis types"
auto d = (a == b); // error: "Can not compare verified types with different basis types"
// Copyright 2026 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
//
// Verified types are compile-time constants, but they can participate in
// runtime operations when mixed with their basis types. The result is
// always the runtime (basis) type, effectively treating the verified value
// as a read-only constant operand.
#include <boost/safe_numbers/verified_integers.hpp>
#include <boost/safe_numbers/iostream.hpp>
#include <iostream>
int main()
{
using namespace boost::safe_numbers;
// A compile-time constant and a runtime value
constexpr auto tax_rate = verified_u32{u32{20}};
auto price = u32{500};
// --- Arithmetic: verified op basis -> basis ---
const auto tax = tax_rate * price / u32{100};
std::cout << "Tax on " << price << " at " << tax_rate << "%: " << tax << '\n';
// --- Arithmetic: basis op verified -> basis ---
constexpr auto discount = verified_u32{u32{50}};
const auto discounted = price - discount;
std::cout << price << " - " << discount << " discount = " << discounted << '\n';
std::cout << '\n';
// --- Comparisons: verified vs basis ---
constexpr auto threshold = verified_u32{u32{1000}};
std::cout << std::boolalpha;
std::cout << price << " < " << threshold << ": " << (price < threshold) << '\n';
std::cout << threshold << " > " << price << ": " << (threshold > price) << '\n';
std::cout << price << " == " << threshold << ": " << (price == threshold) << '\n';
std::cout << '\n';
// --- Bitwise operations: verified vs basis ---
constexpr auto mask = verified_u32{u32{0xFF}};
auto value = u32{0xABCD};
const auto masked = value & mask;
std::cout << "0xABCD & 0xFF = " << masked << '\n';
const auto combined = mask | value;
std::cout << "0xFF | 0xABCD = " << combined << '\n';
// Shift operations
constexpr auto shift = verified_u32{u32{4}};
const auto shifted = value << shift;
std::cout << "0xABCD << 4 = " << shifted << '\n';
std::cout << '\n';
// --- Bounded types work too ---
constexpr auto bounded_offset = verified_bounded_integer<0u, 100u>{10u};
auto bounded_val = bounded_uint<0u, 100u>{50u};
const auto bounded_sum = bounded_val + bounded_offset;
std::cout << "bounded 50 + 10 = " << bounded_sum << '\n';
const auto bounded_diff = bounded_val - bounded_offset;
std::cout << "bounded 50 - 10 = " << bounded_diff << '\n';
// Bounded comparisons
std::cout << "bounded 50 > 10: " << (bounded_val > bounded_offset) << '\n';
return 0;
}
Output:
Tax on 500 at 20%: 100 500 - 50 discount = 450 500 < 1000: true 1000 > 500: true 500 == 1000: false 0xABCD & 0xFF = 205 0xFF | 0xABCD = 44031 0xABCD << 4 = 703696 bounded 50 + 10 = 60 bounded 50 - 10 = 40 bounded 50 > 10: true
Integration with Other Features
Verified types integrate with the library’s other features:
-
<bit>Support: Functions returningintorbool(has_single_bit,bit_width,countl_zero,countl_one,countr_zero,countr_one,popcount) work at runtime with verified types via theirconstexprconversion operator. Functions returning the safe type (bit_ceil,bit_floor,rotl,rotr,byteswap) haveconstevaloverloads for verified types. -
<charconv>Support:to_charsworks at runtime (only reads the value).from_charshas aconstevaloverload for verified types. -
Stream I/O Support:
operator<<works normally at runtime.operator>>is excluded for verified types since they cannot be constructed at runtime. -
<limits>Support:std::numeric_limitsis fully specialized for all verified types, delegating to the basis type’s limits. For verified bounded types,min()andmax()correctly report the bounded range. -
Formatting Support: Both
std::formatand{fmt}work at runtime via theconstexprconversion operator.