Unit Conversion and Dimensional Analysis Library 3.6.1
A compile-time, header-only C++23 dimensional-analysis library
Loading...
Searching...
No Matches
Literals

The user-defined literal operators — 5.0_m, 3_km, 2.0_Te — the scheme that names them, and the metric prefixes they carry.

Every unit in the library gets a user-defined literal operator named _<abbreviation>, where the abbreviation is the unit's short form (m for meters, s for seconds, N for newtons). The literals let a quantity be written as a suffixed numeric literal instead of a constructor call.

#include <units.h>
using namespace units;
using namespace units::literals; // required — see below
int main()
{
auto a = 5.0_m; // meters<double>, 5 m
auto b = 60.0_mi; // miles<double>
auto c = 9.81_mps2; // meters_per_second_squared<double>
(void)a; (void)b; (void)c;
return 0;
}
constexpr meters_per_second c(299792458.0)
Speed of light in vacuum.
namespace for unit literal definitions of all categories.
Unit Conversion Library namespace.
Definition units.h:106
Complete implementation of units - a compile-time, header-only, unit conversion library built on c++2...

The using namespace units::literals; requirement

The literal operators are declared in the nested namespace units::literals, kept separate from the rest of the library so that pulling them in is an explicit, opt-in decision. A literal suffix is only visible once that namespace is in scope:

using namespace units::literals; // bring the operators into scope
auto d = 5.0_m; // now well-formed

Without the using directive, 5.0_m fails to compile with "unable to find numeric literal operator ""_m". You may scope the directive to a function or a block rather than a whole file; ADL does not apply to literal operators, so the directive is the only way to reach them.

Note: The literals are generated by the same UNIT_ADD machinery that defines a unit, so a unit you define yourself automatically gets its own _<abbreviation> literal in units::literals. Defining UNIT_NO_LITERAL_SUPPORT (see configuration) suppresses generation of every literal operator.

Integer versus floating-point: the decimal point decides

Each unit declares two literal operators — one taking long double, one taking unsigned long long — and the form of the numeric literal selects between them:

  • A literal with a decimal point (or exponent) — 5.0_m, 1e3_m — calls the long double overload and yields a unit with a double representation: meters<double>.
  • A literal without a decimal point — 5_m — calls the unsigned long long overload and yields a unit with an int representation: meters<int>.
#include <units.h>
#include <type_traits>
using namespace units;
using namespace units::literals;
int main()
{
auto a = 5_m; // meters<int>
auto b = 5.0_m; // meters<double>
static_assert(std::is_same_v<decltype(a), units::length::meters<int>>);
static_assert(std::is_same_v<decltype(b), units::length::meters<double>>);
(void)a; (void)b;
return 0;
}

Caveat: An integer-representation quantity refuses a lossy implicit conversion. meters<int> x = 1.0_ft; is ill-formed because feet-to-meters would truncate in an integer. When in doubt — especially for anything that will be converted or divided — prefer the floating-point form (5.0_m), which imposes no such restriction.

Metric prefixes

A unit defined with metric prefixes (via UNIT_ADD_WITH_METRIC_PREFIXES) gets a literal for each SI prefix from femto to peta. The literal suffix is _<prefix-symbol><abbreviation> — the prefix symbol prepended to the unit's abbreviation. So meters (_m) also yields _km (kilometers), _mm (millimeters), _um (micrometers), and so on.

Prefix Symbol Factor Example literal
femto f 10⁻¹⁵ 1.0_fm
pico p 10⁻¹² 1.0_pm
nano n 10⁻⁹ 1.0_nm
micro u 10⁻⁶ 1.0_um
milli m 10⁻³ 250_mm
centi c 10⁻² 1.0_cm
deci d 10⁻¹ 1.0_dm
deca da 10¹ 1.0_dam
hecto h 10² 1.0_hm
kilo k 10³ 3.0_km
mega M 10⁶ 1.0_Mm
giga G 10⁹ 1.0_Gm
tera T 10¹² 1.0_Tm
peta P 10¹⁵ 1.0_Pm
#include <units.h>
#include <type_traits>
using namespace units;
using namespace units::literals;
int main()
{
auto km = 3.0_km; // kilometers<double>
auto mm = 250_mm; // millimeters<int>
static_assert(std::is_same_v<decltype(km), units::length::kilometers<double>>);
static_assert(std::is_same_v<decltype(mm), units::length::millimeters<int>>);
(void)km; (void)mm;
return 0;
}

Note: micro uses the ASCII symbol u (_um), not the Greek µ, so the literal is typable on any keyboard. The prefix symbols are case-sensitive: _Mm (megameters) and _mm (millimeters) are different literals, as SI intends.

The tesla exception: _Te

Tesla is the one unit whose literal is not its plain abbreviation. Its abbreviation would be T, but _T collides with a preprocessor macro named _T (the TCHAR text macro from the Windows headers, <tchar.h>/<windows.h>). To avoid that clash, tesla uses Te, so its literal is _Te:

#include <units.h>
#include <type_traits>
using namespace units;
using namespace units::literals;
int main()
{
auto b = 2.0_Te; // teslas<double>
static_assert(std::is_same_v<decltype(b), units::magnetic_field_strength::teslas<double>>);
(void)b;
return 0;
}

Because tesla is prefix-enabled, its prefixed literals prepend the prefix symbol to Te — e.g. _mTe (millitesla), _uTe (microtesla). The T (tera) prefix is unaffected on other units: _Tm is terameters, _Ts is teraseconds.

Caveat: The _T clash is a Windows/<tchar.h> concern (also seen on some ARM toolchains that define _T). It is the reason for the Te spelling; do not expect a _T tesla literal on any platform.

See also