forked from mpusz/mp-units
We had some fun exploring the STD UDLs for potential collisions, we have learnt our lesson and know how to proceed. Now is high time to start behaving and obeying C++ rules.
215 lines
8.4 KiB
ReStructuredText
215 lines
8.4 KiB
ReStructuredText
.. namespace:: units
|
|
|
|
Text Output
|
|
===========
|
|
|
|
Beside providing dimensional analysis and units conversions, the library
|
|
also tries really hard to print any quantity in the most user friendly way.
|
|
|
|
.. note::
|
|
|
|
The library provides no text output for quantity points.
|
|
|
|
Output Streams
|
|
--------------
|
|
|
|
The easiest way to print a quantity is to provide its object to the output
|
|
stream::
|
|
|
|
using namespace units::physical::si::literals;
|
|
using namespace units::physical::international::literals;
|
|
constexpr Speed auto v1 = avg_speed(220._q_km, 2_q_h);
|
|
constexpr Speed auto v2 = avg_speed(140._q_mi, 2_q_h);
|
|
std::cout << v1 << '\n'; // 110 km/h
|
|
std::cout << v2 << '\n'; // 70 mi/h
|
|
|
|
The text output will always print the :term:`value of a quantity` followed
|
|
by a space and then the symbol of a :term:`unit` associated with this quantity.
|
|
|
|
.. important::
|
|
|
|
Remember that it is a good practice to always `quantity_cast()` a quantity
|
|
of an unknown ``auto`` type before passing it to the text output::
|
|
|
|
std::cout << quantity_cast<si::kilometre_per_hour>(v1) << '\n'; // 110 km/h
|
|
std::cout << quantity_cast<si::metre_per_second>(v1) << '\n'; // 30.5556 m/s
|
|
|
|
|
|
Stream Output Formatting
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Only a basic formatting can be applied for output streams. It includes control
|
|
over width, fill, and alignment::
|
|
|
|
os << "|" << std::setw(10) << 123_q_m << "|"; // | 123 m|
|
|
os << "|" << std::setw(10) << std::left << 123_q_m << "|"; // |123 m |
|
|
os << "|" << std::setw(10) << std::setfill('*') << 123_q_m << "|"; // |*****123 m|
|
|
|
|
|
|
fmt::format
|
|
-----------
|
|
|
|
The **mp-units** via ``fmt::format`` provides a fine-grained control over what
|
|
and how is being printed on the text output.
|
|
|
|
|
|
Grammar
|
|
^^^^^^^
|
|
|
|
.. productionlist::
|
|
units-format-spec: [fill-and-align] [width] [units-specs]
|
|
units-specs: conversion-spec
|
|
: units-specs conversion-spec
|
|
: units-specs literal-char
|
|
literal-char: any character other than '{' or '}'
|
|
conversion-spec: '%' units-type
|
|
units-type: [units-rep-modifier] 'Q'
|
|
: [units-unit-modifier] 'q'
|
|
: one of "nt%"
|
|
units-rep-modifier: [sign] [#] [precision] [units-rep-type]
|
|
units-rep-type: one of "aAbBdeEfFgGoxX"
|
|
units-unit-modifier: 'A'
|
|
|
|
In the above grammar:
|
|
|
|
- ``fill-and-align``, ``width``, ``sign``, ``#``, and ``precision`` tokens and
|
|
individual tokens of :token:`units-rep-type` are defined in the
|
|
`format.string.std <https://wg21.link/format.string.std>`_ chapter of the C++
|
|
standard specification,
|
|
- tokens ``Q``, ``q``, ``n``, ``t``, and ``%`` of :token:`units-type` are described
|
|
in the `time.format <https://wg21.link/time.format>`_ chapter of the C++ standard
|
|
specification,
|
|
- ``A`` token of :token:`units-unit-modifier` forces ASCII-only output (instead of the
|
|
default Unicode symbols defined by the :term:`SI` specification).
|
|
|
|
|
|
Default formatting
|
|
^^^^^^^^^^^^^^^^^^
|
|
|
|
To format `quantity` values the formatting facility uses :token:`units-format-spec`.
|
|
In case it is left empty the default formatting of ``{:%Q %q}`` is applied. The same
|
|
default formatting is also applied to the output streams. This is why the following
|
|
code lines produce the same output::
|
|
|
|
std::cout << "Distance: " << 123_q_km << "\n";
|
|
fmt::print("Distance: {}\n", 123_q_km);
|
|
fmt::print("Distance: {:%Q %q}\n", 123_q_km);
|
|
|
|
|
|
Quantity Value, Symbol, or Both?
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The user can easily decide to either print a whole quantity (value and symbol) or
|
|
only its parts. Also a different quantity formatting might be applied::
|
|
|
|
fmt::print("{:%Q}", 123_q_km); // 123
|
|
fmt::print("{:%q}", 123_q_km); // km
|
|
fmt::print("{:%Q%q}", 123_q_km); // 123km
|
|
|
|
|
|
Controlling Width, Fill, and Alignment
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
To control width, fill, and alignment the C++ standard grammar tokens ``fill-and-align``
|
|
and ``width`` are being used and they treat a quantity value and symbol as a contiguous
|
|
text::
|
|
|
|
fmt::print("|{:0}|", 123_q_m); // |123 m|
|
|
fmt::print("|{:10}|", 123_q_m); // | 123 m|
|
|
fmt::print("|{:<10}|", 123_q_m); // |123 m |
|
|
fmt::print("|{:>10}|", 123_q_m); // | 123 m|
|
|
fmt::print("|{:^10}|", 123_q_m); // | 123 m |
|
|
fmt::print("|{:*<10}|", 123_q_m); // |123 m*****|
|
|
fmt::print("|{:*>10}|", 123_q_m); // |*****123 m|
|
|
fmt::print("|{:*^10}|", 123_q_m); // |**123 m***|
|
|
|
|
|
|
ASCII-only Quantity Symbols
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Unit symbols of some quantities are specified to use Unicode signs by the :term:`SI`
|
|
standard (i.e. ``Ω`` symbol for the resistance quantity). **mp-units** library follows
|
|
this by default. From the engineering point of view sometimes Unicode text might
|
|
not be a solution as terminals of many (especially embedded) devices are ASCII-only.
|
|
In such a case the unit symbol can be forced to be printed using ASCII-only characters::
|
|
|
|
fmt::print("{}", 10_q_R); // 10 Ω
|
|
fmt::print("{:%Q %Aq}", 10_q_R); // 10 ohm
|
|
fmt::print("{}", 125_q_us); // 125 µs
|
|
fmt::print("{:%Q %Aq}", 125_q_us); // 125 us
|
|
fmt::print("{}", 9.8_q_m_per_s2); // 9.8 m/s²
|
|
fmt::print("{:%Q %Aq}", 9.8_q_m_per_s2); // 9.8 m/s^2
|
|
|
|
|
|
Controlling on How the Quantity Value Is Being Printed
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
``sign`` token allows us to specify on how the value's sign is being printed::
|
|
|
|
fmt::print("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", 1_q_m); // 1 m,+1 m,1 m, 1 m
|
|
fmt::print("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", -1_q_m); // -1 m,-1 m,-1 m,-1 m
|
|
|
|
where:
|
|
|
|
- ``+`` indicates that a sign should be used for both non-negative and negative numbers,
|
|
- ``-`` indicates that a sign should be used for negative numbers and negative zero only
|
|
(this is the default behavior),
|
|
- ``<space>`` indicates that a leading space should be used for non-negative numbers other
|
|
than negative zero, and a minus sign for negative numbers and negative zero.
|
|
|
|
``precision`` token is allowed only for floating-point representation types::
|
|
|
|
fmt::print("{:%.0Q %q}", 1.2345_q_m); // 1 m
|
|
fmt::print("{:%.1Q %q}", 1.2345_q_m); // 1.2 m
|
|
fmt::print("{:%.2Q %q}", 1.2345_q_m); // 1.23 m
|
|
|
|
|
|
:token:`units-rep-type` specifies how a value of the representation type is being
|
|
printed. For integral types::
|
|
|
|
fmt::print("{:%bQ %q}", 42_q_m); // 101010 m
|
|
fmt::print("{:%BQ %q}", 42_q_m); // 101010 m
|
|
fmt::print("{:%dQ %q}", 42_q_m); // 42 m
|
|
fmt::print("{:%oQ %q}", 42_q_m); // 52 m
|
|
fmt::print("{:%xQ %q}", 42_q_m); // 2a m
|
|
fmt::print("{:%XQ %q}", 42_q_m); // 2A m
|
|
|
|
The above can be printed in an alternate version thanks to the ``#`` token::
|
|
|
|
fmt::print("{:%#bQ %q}", 42_q_m); // 0b101010 m
|
|
fmt::print("{:%#BQ %q}", 42_q_m); // 0B101010 m
|
|
fmt::print("{:%#oQ %q}", 42_q_m); // 052 m
|
|
fmt::print("{:%#xQ %q}", 42_q_m); // 0x2a m
|
|
fmt::print("{:%#XQ %q}", 42_q_m); // 0X2A m
|
|
|
|
For floating-point values the :token:`units-rep-type` token works as follows::
|
|
|
|
fmt::print("{:%aQ %q}", 1.2345678_q_m); // 0x9.e065152d8eae841p-3 m
|
|
fmt::print("{:%.3aQ %q}", 1.2345678_q_m); // 0x9.e06p-3 m
|
|
fmt::print("{:%AQ %q}", 1.2345678_q_m); // 0X9.E065152D8EAE841P-3 m
|
|
fmt::print("{:%.3AQ %q}", 1.2345678_q_m); // 0X9.E06P-3 m
|
|
fmt::print("{:%eQ %q}", 1.2345678_q_m); // 1.234568e+00 m
|
|
fmt::print("{:%.3eQ %q}", 1.2345678_q_m); // 1.235e+00 m
|
|
fmt::print("{:%EQ %q}", 1.2345678_q_m); // 1.234568E+00 m
|
|
fmt::print("{:%.3EQ %q}", 1.2345678_q_m); // 1.235E+00 m
|
|
fmt::print("{:%gQ %q}", 1.2345678_q_m); // 1.23457 m
|
|
fmt::print("{:%gQ %q}", 1.2345678e8_q_m); // 1.23457e+08 m
|
|
fmt::print("{:%.3gQ %q}", 1.2345678_q_m); // 1.23 m
|
|
fmt::print("{:%.3gQ %q}", 1.2345678e8_q_m); // 1.23e+08 m
|
|
fmt::print("{:%GQ %q}", 1.2345678_q_m); // 1.23457 m
|
|
fmt::print("{:%GQ %q}", 1.2345678e8_q_m); // 1.23457E+08 m
|
|
fmt::print("{:%.3GQ %q}", 1.2345678_q_m); // 1.23 m
|
|
fmt::print("{:%.3GQ %q}", 1.2345678e8_q_m); // 1.23E+08 m
|
|
|
|
|
|
Special Signs
|
|
^^^^^^^^^^^^^
|
|
|
|
Beside adding any list of regular characters as a separator between the value and the
|
|
symbol, it is possible to type a few special signs there too::
|
|
|
|
fmt::print("{:%Q_%q}", 123_q_km); // 123_km
|
|
fmt::print("{:%Q%t%q}", 123_q_km); // 123\tkm <tab>
|
|
fmt::print("{:%Q%n%q}", 123_q_km); // 123\nkm <new line>
|
|
fmt::print("{:%Q%% %q}", 123_q_km); // 123% km
|