User-Defined Literals
Description
The library provides user-defined literal suffixes for concise construction of safe integer types.
The literals are defined in the boost::safe_numbers::literals namespace.
The behavior of the literals depends on the type:
-
For
_u8,_u16, and_u32, the literal value is range-checked and throwsstd::overflow_errorif the value exceeds the target type’s maximum. -
The
_u64literal performs no range check sinceunsigned long longmaps directly tostd::uint64_t(statically verified). -
The
_u128literal parses a string representation and throwsstd::overflow_erroron overflow orstd::invalid_argumenton invalid input.
#include <boost/safe_numbers/literals.hpp>
namespace boost::safe_numbers::literals {
constexpr auto operator ""_u8(unsigned long long int val) -> u8;
constexpr auto operator ""_u16(unsigned long long int val) -> u16;
constexpr auto operator ""_u32(unsigned long long int val) -> u32;
constexpr auto operator ""_u64(unsigned long long int val) noexcept -> u64;
constexpr auto operator ""_u128(const char* str) -> u128;
} // namespace boost::safe_numbers::literals
Literal Suffixes
| Suffix | Result Type | Range Check |
|---|---|---|
|
|
Throws |
|
|
Throws |
|
|
Throws |
|
|
No range check (direct conversion from |
|
|
Parses string; throws |
Usage
To use the literals, bring the boost::safe_numbers::literals namespace into scope:
using namespace boost::safe_numbers::literals;
constexpr auto a {42_u8};
constexpr auto b {1000_u16};
constexpr auto c {100000_u32};
constexpr auto d {9999999999_u64};
constexpr auto e {340282366920938463463374607431768211455_u128};
Literals are constexpr and can be used in compile-time contexts.
When used in a constexpr context, an out-of-range value produces a compile error rather than a runtime exception.
Examples
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// This example demonstrates the use of user-defined literals for
// constructing safe integer types. The literals provide a concise
// syntax and perform compile-time range checking when possible.
#include <boost/safe_numbers/unsigned_integers.hpp>
#include <boost/safe_numbers/literals.hpp>
#include <boost/safe_numbers/iostream.hpp>
#include <iostream>
int main()
{
using namespace boost::safe_numbers;
using namespace boost::safe_numbers::literals;
// Construct safe integers using literal suffixes
{
constexpr auto a {42_u8};
constexpr auto b {1000_u16};
constexpr auto c {100000_u32};
constexpr auto d {9999999999_u64};
constexpr auto e {340282366920938463463374607431768211455_u128};
std::cout << "42_u8 = " << a << std::endl;
std::cout << "1000_u16 = " << b << std::endl;
std::cout << "100000_u32 = " << c << std::endl;
std::cout << "9999999999_u64 = " << d << std::endl;
std::cout << "max_u128 = " << e << std::endl;
}
// Literals work naturally in expressions
{
const auto sum {100_u32 + 50_u32};
const auto product {6_u32 * 7_u32};
std::cout << "100_u32 + 50_u32 = " << sum << std::endl;
std::cout << "6_u32 * 7_u32 = " << product << std::endl;
}
// Literals are constexpr - can be used in compile-time contexts
{
constexpr auto compile_time {255_u8};
static_assert(compile_time == u8{255U});
constexpr auto zero {0_u32};
static_assert(zero == u32{0U});
std::cout << "constexpr 255_u8 = " << compile_time << std::endl;
}
// NOTE: Out-of-range literals throw std::overflow_error at runtime,
// or produce a compile error when used in constexpr context:
//
// auto bad = 256_u8; // throws std::overflow_error (> UINT8_MAX)
// auto bad = 70000_u16; // throws std::overflow_error (> UINT16_MAX)
return 0;
}
Output:
42_u8 = 42 1000_u16 = 1000 100000_u32 = 100000 9999999999_u64 = 9999999999 max_u128 = 340282366920938463463374607431768211455 100_u32 + 50_u32 = 150 6_u32 * 7_u32 = 42 constexpr 255_u8 = 255