Literals

The following literals and macros are provided for convenient construction of the types provided in the library.

#include <boost/int128/literals.hpp>

namespace boost {
namespace int128 {
namespace literals {

BOOST_INT128_HOST_DEVICE constexpr uint128_t operator ""_u128(const char* str) noexcept;

BOOST_INT128_HOST_DEVICE constexpr uint128_t operator ""_U128(const char* str) noexcept;

BOOST_INT128_HOST_DEVICE constexpr uint128_t operator ""_u128(const char* str, std::size_t len) noexcept;

BOOST_INT128_HOST_DEVICE constexpr uint128_t operator ""_U128(const char* str, std::size_t len) noexcept;

BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(const char* str) noexcept;

BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(const char* str) noexcept;

BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(const char* str, std::size_t len) noexcept;

BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(const char* str, std::size_t len) noexcept;

} // namespace literals
} // namespace int128
} // namespace boost

#define BOOST_INT128_UINT128_C(x) ...
#define BOOST_INT128_INT128_C(x) ...

The macros at the end allow you to write out a 128-bit number like you would with say UINT64_C without having to add quotes.

Bases

The literals accept the standard C++ integer base prefixes in addition to plain decimal. A 0x or 0X prefix selects hexadecimal, 0b or 0B selects binary, and a leading 0 selects octal. The prefix is stripped and the remaining digits are parsed in the selected base. Digit separators (') may be used in any base.

0xDEAD'BEEF_u128    // hexadecimal, == 3735928559
0b1111'0000_u128    // binary,      == 240
0777_u128           // octal,       == 511
255_u128            // decimal,     == 255
-0xFF_i128          // == -255 (the unary minus is applied after parsing)
"-0b1010"_i128      // == -10 (the string form may embed the sign)

Error Handling

An invalid literal is rejected at compile time rather than being silently accepted. This includes a value that overflows the target type, a digit that is not valid for the selected base (for example 0b2 or 09), and an empty magnitude such as 0x. When such a literal is used in a constant expression the parse reaches BOOST_INT128_UNREACHABLE, which is not a constant expression and therefore is a hard compile error.

The minimum int128_t value cannot be written as a negated _i128 literal, because its positive magnitude (2^127) exceeds the maximum int128_t value and so fails to parse (a hard compile error in a constant expression). Use BOOST_INT128_INT128_C(-170141183460469231731687303715884105728), the string form "-170141183460469231731687303715884105728"_i128, or (std::numeric_limits<int128_t>::min)() instead.

See the construction examples for usage demonstrations of both literals and macros.

Design Rationale

All of the user-defined literals provided by the library are string-form: the operator receives a const char* and parses the digit sequence via from_chars. This holds even for raw numeric tokens like 12345_U128, which the compiler forwards to the operator as the string "12345". The choice is intentional. A 128-bit value cannot be represented by unsigned long long, so any literal whose magnitude exceeds 2^64 must go through a string-based parse. Providing only the string form means there is a single overload that handles every magnitude uniformly, rather than a numeric form for small values and a string form for large ones with a hard cutoff at 2^64. The API is the same regardless of how large the value is. The trade-off is that every literal pays the cost of parsing, even when the value would fit in a builtin integer. For values smaller than 2^64, prefer the constructor:

constexpr uint128_t small {42U};            // direct conversion from a builtin
const auto small_literal {42_U128};         // parses "42" and then constructs

The two produce the same value, but the constructor avoids the parse and should be used in hot paths or in code where many small constants are constructed.