Skip to content

literals.hpp

User-defined literals for shulib units. Each converts to CANONICAL units at the point of writing, so the rest of the code never sees a raw unit again: distance = 24_in; field = 1_tile; dt = 20_ms; v = 12_volt;.

This header declares 14 free functions.

Extracted from include/shulib/units/literals.hpp — this page is that header's documentation, reformatted, so it cannot disagree with the code. Prose about how to think about the API lives in the user guide; worked recipes live in the cookbook; this page is the complete, mechanical list of what exists.

Contents

operator""_in

constexpr Length operator""_in(long double v) noexcept

Inches — THE canonical length unit, so 24_in stores exactly 24.0 and nothing converts.

free function, declared at include/shulib/units/literals.hpp:22.

operator""_in (overload 2)

constexpr Length operator""_in(unsigned long long v) noexcept

Integer spelling of _in, and NOT redundant with the overload above: C++ offers an integer literal only to the unsigned long long form, so without this one 24_in would not compile — it is never quietly converted to the long double operator. That the parameter is unsigned is also why there is no negative literal: -24_in is unary minus applied to Length{24.0}, which works only because Length is a signed displacement.

free function, declared at include/shulib/units/literals.hpp:28.

operator""_tile

constexpr Length operator""_tile(long double v) noexcept

Foam field tiles, converted HERE: one tile is 24 inches, so 1_tile is Length{24.0}. The result is an ordinary Length — nothing downstream ever knows a tile was mentioned.

free function, declared at include/shulib/units/literals.hpp:31.

operator""_tile (overload 2)

constexpr Length operator""_tile(unsigned long long v) noexcept

Integer spelling of _tile; 2_tile is 48 inches.

free function, declared at include/shulib/units/literals.hpp:33.

operator""_s

constexpr Time operator""_s(long double v) noexcept

Seconds — the canonical time unit, so 2_s stores exactly 2.0.

free function, declared at include/shulib/units/literals.hpp:37.

operator""_s (overload 2)

constexpr Time operator""_s(unsigned long long v) noexcept

Integer spelling of _s, which C++ forces to be a SEPARATE overload — a literal written with no decimal point is offered only to the unsigned long long form and never converted to the long double one above. Nothing is computed on the way in, so 2_s is exactly 2.0, and the integer-to-double conversion stays exact far past any duration a match can run.

free function, declared at include/shulib/units/literals.hpp:42.

operator""_ms

constexpr Time operator""_ms(long double v) noexcept

Milliseconds, divided by 1000 AT THE LITERAL: 20_ms is Time{0.02}. This is where the "internal seconds, always" rule is enforced — no millisecond value reaches a gain or a dt.

free function, declared at include/shulib/units/literals.hpp:45.

operator""_ms (overload 2)

constexpr Time operator""_ms(unsigned long long v) noexcept

Integer spelling of _ms — the form a loop period is normally written in (10_ms).

free function, declared at include/shulib/units/literals.hpp:47.

operator""_volt

constexpr Voltage operator""_volt(long double v) noexcept

Volts — canonical, so 12_volt stores 12.0. It does NOT clamp: the ±12 V ceiling is applied by IMotor::setVoltage (hal::kMaxMotorVoltage), never by writing the literal.

free function, declared at include/shulib/units/literals.hpp:52.

operator""_volt (overload 2)

constexpr Voltage operator""_volt(unsigned long long v) noexcept

Integer spelling of _volt — the form the rail voltage is normally written in — and required as its own overload, since an integer literal is never offered to the long double operator above. It does NOT clamp either: 13_volt builds Voltage{13.0} and only IMotor::setVoltage applies the ±kMaxMotorVoltage ceiling. Reverse is -12_volt, which is unary minus on Voltage{12.0} rather than a negative literal — the parameter here is unsigned.

free function, declared at include/shulib/units/literals.hpp:58.

operator""_deg

inline ::shulib::math::Angle operator""_deg(long double v)

Degrees as a WRAPPING math::Angle rather than a bare Quantity, so 90_deg is a heading and not a scalar: it normalizes to (-π, π] on construction, which means 359_deg stores -1°. Degrees exist only at this boundary — the value inside is radians.

free function, declared at include/shulib/units/literals.hpp:64.

operator""_deg (overload 2)

inline ::shulib::math::Angle operator""_deg(unsigned long long v)

Integer spelling of _deg. The angle literals are the only ones here that are NOT constexpr — Angle's factories run a runtime finiteness check — so 90_deg cannot initialize a constexpr variable the way 24_in can.

free function, declared at include/shulib/units/literals.hpp:70.

operator""_rad

inline ::shulib::math::Angle operator""_rad(long double v)

Radians as a wrapping math::Angle, with no conversion (3_rad stores 3.0) but the SAME normalization as _deg, so 7_rad stores 7 − 2π ≈ 0.717. There is no literal here that builds an un-wrapped heading; use units::AngleDim for a rate or an accumulated total.

free function, declared at include/shulib/units/literals.hpp:76.

operator""_rad (overload 2)

inline ::shulib::math::Angle operator""_rad(unsigned long long v)

Integer spelling of _rad. Same type as _deg produces, so the two are interchangeable wherever an Angle is taken; also not constexpr (see _deg).

free function, declared at include/shulib/units/literals.hpp:81.

Design commentary, from the header

The header opens with the reasoning behind these shapes. It is reproduced here in full because a reference that only lists signatures teaches nobody why.

The header’s own reasoning — 12 lines
 User-defined literals for shulib units. Each converts to CANONICAL units at
 the point of writing, so the rest of the code never sees a raw unit again:
   distance = 24_in;  field = 1_tile;  dt = 20_ms;  v = 12_volt;

 `_ms` divides by 1000 -> seconds, enforcing the "internal seconds, always"
 decision at the literal boundary. `_deg`/`_rad` build an (auto-wrapped)
 shulib::math::Angle, NOT a bare Quantity (decision §13 #3).

 Each literal has two forms: a floating (long double) and an integer
 (unsigned long long), so both `24_in` and `24.0_in` compile. The narrowing
 to double is made explicit (the build is -Wconversion -Werror).

Last updated 2026-08-15 — published from the main release branch, commit fa545ff. This site tracks releases, so between them it can lag the repository — that lag is deliberate, and it is what keeps the development log off the public site. For the current state of the code, see the repository.