User-Defined Literals
beman::big_int provides user-defined literals that let you write a big_int
constant directly in source code, free of the range limits of the built-in
integer literals. A literal such as 123_n parses its digits at compile time
and yields a big_int (the alias for basic_big_int over the default
allocator).
Synopsis
namespace beman::big_int {
inline namespace literals {
inline namespace big_int_literals {
template <char... digits>
constexpr big_int operator""n() noexcept(/* fits without allocating */);
template <char... digits>
constexpr big_int operator""N() noexcept(/* fits without allocating */);
template <char... digits>
constexpr big_int operator""_n() noexcept(/* fits without allocating */);
template <char... digits>
constexpr big_int operator""_N() noexcept(/* fits without allocating */);
} // namespace big_int_literals
} // namespace literals
} // namespace beman::big_int
All four operators are templated on the literal’s digit sequence, so the value is known to the compiler and is validated and parsed during translation.
Bringing the literals into scope
The operators are declared in the inline namespace
beman::big_int::literals. As with the standard library’s literal operators,
the recommended way to use them is a single using-directive:
using namespace beman::big_int::literals;
auto x = 123_n; // x is a beman::big_int::big_int
Because the namespace is inline, the qualified names
beman::big_int::literals and beman::big_int::big_int_literals refer to the
same set of operators.
The n, N, _n, and _N suffixes
The four suffixes are equivalent: N, _n, and _N delegate to operator""n,
so every spelling of a literal yields the same value, the same type, and the same
exception specification. They exist so that portable code has a suffix it can
always rely on, in whichever case the surrounding literals are written:
| Suffix | Description |
|---|---|
|
The suffix intended by the C++29 proposal. A bare suffix that begins with a letter is reserved to the implementation, which is exactly what a standard-library literal is, so it is the natural spelling |
|
Upper-case spelling of |
|
Portable spelling of |
|
Portable spelling of |
The underscored suffixes are provided because some compilers do not yet accept a
literal suffix which does not begin with an underscore at the point of use; Clang
rejects 123n and 123N outright
(llvm/llvm-project#76394),
even though the operators themselves compile there. Prefer _n or _N when you
need code that compiles everywhere today.
using namespace beman::big_int::literals;
auto lower = 0xdead'beef_n;
auto upper = 0xDEAD'BEEF_N; // same value, same type
Bases, separators, and sign
The text between the suffix and any leading sign follows the same grammar as a
built-in integer literal. The examples below use _n, but every suffix accepts
exactly the same literals:
-
Base. Digits are decimal (base 10) by default. A
0x(or0X) prefix selects hexadecimal,0b(or0B) selects binary, and a leading0selects octal. Letters in a hexadecimal literal may be written in either case. -
Digit separators. A single quote (
') may appear between two digits to group them, exactly as in1'000'000_n. The separators are removed before parsing. -
Sign. A literal is always non-negative; there is no sign inside the literal. Write a negative value by applying unary minus to the literal, as in
-42_n.
using namespace beman::big_int::literals;
auto a = 255_n; // decimal
auto b = 0xFF_n; // hexadecimal, equal to a
auto c = 0b1111'1111_n; // binary, equal to a
auto d = 0377_n; // octal, equal to a
auto e = -1'000'000_n; // unary minus applied to 1000000_n
Compile-time evaluation
A literal is always parsed and validated during translation; an ill-formed literal (for example, one containing a digit that is invalid for its base) is a compile-time error rather than a runtime failure.
A literal whose value is small enough to fit in big_int 's inline storage is a true constant expression and can initialize a constexpr variable.
Such a literal also constructs without allocating, so operator""n is noexcept for it.
A literal too large for the inline storage will allocate, and when declared as constexpr big_int …,
the value must be destroyed before run-time, as allocations are non-transient.
That construction allocates, so the operator is potentially-throwing for such literals.
The delegating suffixes carry the same exception specification, so noexcept(123_N)
and noexcept(123n) agree with noexcept(123_n) for every literal.