Formatting Support
Description
Boost.SafeNumbers supports formatting with both <format> (C++20 and later) and <fmt/format.h> (all language standards).
The formatters delegate to the underlying integer type’s formatter, so all standard integer format specifiers are supported.
std::format is supported when using C++20 or later with a compiler that has appropriate support: GCC >= 13, Clang >= 18, MSVC >= 19.40.
#include <boost/safe_numbers/format.hpp> // For std::format support
#include <boost/safe_numbers/fmt_format.hpp> // For fmt::format support
Synopsis
// <boost/safe_numbers/format.hpp>
template <unsigned_integral BasisType>
struct std::formatter<boost::safe_numbers::detail::unsigned_integer_basis<BasisType>>
: std::formatter<BasisType>
{
auto format(const unsigned_integer_basis<BasisType>& val,
std::format_context& ctx) const;
};
// <boost/safe_numbers/fmt_format.hpp>
template <unsigned_integral BasisType>
struct fmt::formatter<boost::safe_numbers::detail::unsigned_integer_basis<BasisType>>
: fmt::formatter<BasisType>
{
auto format(const unsigned_integer_basis<BasisType>& val,
fmt::format_context& ctx) const;
};
Type Modifiers
The following type modifiers are supported (same as built-in integer types):
| Modifier | Format | Example |
|---|---|---|
|
Decimal (default) |
|
|
Lowercase hexadecimal |
|
|
Uppercase hexadecimal |
|
|
Octal |
|
|
Lowercase binary |
|
|
Uppercase binary |
|
Example usage for hexadecimal format: {:x}
Alternate Form
Use # to enable alternate form which adds a prefix:
| Format | Prefix |
|---|---|
|
|
|
|
|
|
|
|
|
|
Padding and Alignment
Values can be padded to a fixed width with optional alignment:
| Specifier | Alignment | Example (val = 42) |
|---|---|---|
|
Right (default) |
` 42` |
|
Left |
`42 ` |
|
Center |
` 42 ` |
|
Right with zero fill |
|
Fill Character
A custom fill character can be specified before the alignment:
-
{:*>10}produces**42 -
{:_<10}produces42__
Sign Modifier
For unsigned types, sign modifiers have limited effect since values are always non-negative:
| Modifier | Effect |
|---|---|
|
Always show sign (shows |
|
Only show sign for negative (no effect for unsigned) |
` ` |
Space for positive, minus for negative |
Locale Modifier
Use L to apply locale-specific formatting (e.g., thousand separators):
std::locale::global(std::locale("en_US.UTF-8"));
std::cout << std::format("{:L}", u32{1234567}); // "1,234,567"
Format Specifier Order
The full format specifier order is:
{[fill][align][sign][#][0][width][.precision][L][type]}
Examples
The header <boost/safe_numbers/fmt_format.hpp> is NOT part of the convenience header, because it is an optional dependency on a potentially compiled library.
|
// Copyright 2026 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define FMT_HEADER_ONLY
#if __has_include(<fmt/format.h>)
#include <boost/safe_numbers/unsigned_integers.hpp>
#include <boost/safe_numbers/fmt_format.hpp>
#include <fmt/format.h>
#include <iostream>
int main()
{
using namespace boost::safe_numbers;
const u32 val1 {12345};
const u64 val2 {9876543210};
// Default format (decimal)
std::cout << "Default Format:\n";
std::cout << fmt::format("{}", val1) << '\n';
std::cout << fmt::format("{}", val2) << "\n\n";
// Hexadecimal format
std::cout << "Hexadecimal Format:\n";
std::cout << fmt::format("{:x}", val1) << '\n';
std::cout << fmt::format("{:#x}", val2) << "\n\n";
// Binary format
std::cout << "Binary Format:\n";
std::cout << fmt::format("{:b}", val1) << '\n';
std::cout << fmt::format("{:#b}", u8{42}) << "\n\n";
// Octal format
std::cout << "Octal Format:\n";
std::cout << fmt::format("{:o}", val1) << '\n';
std::cout << fmt::format("{:#o}", val1) << "\n\n";
// Padding and alignment
std::cout << "Padding and Alignment:\n";
std::cout << fmt::format("{:>10}", val1) << '\n'; // Right align
std::cout << fmt::format("{:<10}", val1) << '\n'; // Left align
std::cout << fmt::format("{:^10}", val1) << '\n'; // Center align
std::cout << fmt::format("{:0>10}", val1) << "\n\n"; // Zero-padded
// Fill character
std::cout << "Fill Character:\n";
std::cout << fmt::format("{:*>10}", val1) << '\n';
std::cout << fmt::format("{:_<10}", val1) << '\n';
return 0;
}
#else
#include <iostream>
int main()
{
std::cout << "{fmt} headers are required to run this example." << std::endl;
}
#endif
Output:
Default Format:
12345
9876543210
Hexadecimal Format:
3039
0x24cb016ea
Binary Format:
11000000111001
0b101010
Octal Format:
30071
030071
Padding and Alignment:
12345
12345
12345
0000012345
Fill Character:
*****12345
12345_____
This same example can be run with <format> by replacing fmt::format with std::format and including <boost/safe_numbers/format.hpp> instead.