From c4e9ff7f66c0ee34d8d91c0d6598f1befde2dd53 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 2 Apr 2021 13:11:20 +0200 Subject: [PATCH] docs: Documentation now prefers refrences over UDLs --- docs/faq.rst | 2 +- docs/framework/conversions_and_casting.rst | 59 ++++---- docs/framework/dimensions.rst | 32 ++--- docs/framework/quantities.rst | 122 +++++++++++------ docs/framework/quantity_points.rst | 4 +- docs/framework/text_output.rst | 127 +++++++++--------- docs/framework/units.rst | 4 +- .../use_cases/custom_representation_types.rst | 2 +- docs/use_cases/extensions.rst | 2 +- docs/use_cases/interoperability.rst | 8 +- docs/use_cases/linear_algebra.rst | 12 +- docs/use_cases/unknown_dimensions.rst | 12 +- 12 files changed, 211 insertions(+), 175 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index d1784c86..0aab20c8 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -49,7 +49,7 @@ Why a dimensionless quantity is not just an fundamental arithmetic type? In the initial design of this library the resulting type of the division of two quantities was their common representation type:: - static_assert(std::is_same_v); + static_assert(std::is_same_v); The reasoning behind it was to not provide a false impression of a strong `quantity` type for something that looks and feels like a regular number. Also all of the mathematic diff --git a/docs/framework/conversions_and_casting.rst b/docs/framework/conversions_and_casting.rst index 6114a161..ecc2b348 100644 --- a/docs/framework/conversions_and_casting.rst +++ b/docs/framework/conversions_and_casting.rst @@ -21,9 +21,9 @@ No Conversions No conversions (either implicit or explicit) are available across quantities of different dimensions:: - si::length d1 = 1_q_s; // Compile-time error - si::length d2(1_q_s); // Compile-time error - auto d3 = quantity_cast(1_q_s); // Compile-time error + si::length d1 = 1 * s; // Compile-time error + si::length d2(1 * s); // Compile-time error + auto d3 = quantity_cast(1 * s); // Compile-time error Implicit @@ -33,23 +33,23 @@ Implicit conversions are allowed only across quantities of the same dimension: - for integral types with ratios that guarantee no precision loss:: - si::length d1 = 1_q_km + 1_q_m; // OK - si::length d2 = 1_q_km + 1_q_m; // OK - si::length d3 = 1_q_km + 1_q_m; // Compile-time error - si::length d4(1_q_km + 1_q_m); // Compile-time error - si::length d5 = 1_q_m + 1_q_ft; // Compile-time error - si::length d6(1_q_m + 1_q_ft); // Compile-time error + si::length d1 = 1 * km + 1 * m; // OK + si::length d2 = 1 * km + 1 * m; // OK + si::length d3 = 1 * km + 1 * m; // Compile-time error + si::length d4(1 * km + 1 * m); // Compile-time error + si::length d5 = 1 * m + 1 * ft; // Compile-time error + si::length d6(1 * m + 1 * ft); // Compile-time error - from an integral to a floating-point representation even in case of a truncating ratio:: - si::length d7 = 1_q_km + 1_q_m; // OK - si::length d8 = 1_q_m + 1_q_ft; // OK + si::length d7 = 1 * km + 1 * m; // OK + si::length d8 = 1 * m + 1 * ft; // OK - when both sides use a floating-point representation:: - si::length d9 = 1.23_q_m; // Compile-time error - si::length d10 = 1.23_q_m; // OK + si::length d9 = 1.23 * m; // Compile-time error + si::length d10 = 1.23 * m; // OK Explicit @@ -60,8 +60,8 @@ Explicit conversions are available with the `quantity_cast`, `quantity_point_cas They are especially useful to force a truncating conversion across quantities of the same dimension for integral representation types and ratios that may cause precision loss:: - si::length d1 = quantity_cast(1km + 1m); // OK - si::length d2 = quantity_cast(1s); // Error + si::length d1 = quantity_cast(1 * km + 1 * m); // OK + si::length d2 = quantity_cast(1 * s); // Error .. seealso:: @@ -97,14 +97,13 @@ once and leave the rest intact: `quantity_point_cast` takes anything that works for `quantity_point` or a specific target `quantity_point`:: - std::cout << "Point: " << quantity_point_cast(d) << '\n'; + std::cout << "Point: " << quantity_point_cast(d) << '\n'; -For a single explicit template argument, -`quantity_point_kind_cast` is a superset of `quantity_kind_cast`, -which is also a superset of `quantity_cast`. +For a single explicit template argument, `quantity_point_kind_cast` is a superset of +`quantity_kind_cast`, which is also a superset of `quantity_cast`. For the (dimension, unit) pair of explicit arguments case of `quantity_cast`, -`quantity_point_kind_cast` and `quantity_kind_cast` -accept a `PointKind` and `Kind` instead of a `Dimension`, respectively. +`quantity_point_kind_cast` and `quantity_kind_cast` accept a `PointKind` and `Kind` +instead of a `Dimension`, respectively. .. seealso:: @@ -121,8 +120,8 @@ As noted in the :ref:`framework/quantities:Dimensionless Quantities` chapter, for quantities. However, as they represent numbers it would be highly uncomfortable to every time type:: - const auto d1 = 10_q_km; - const auto d2 = 3_q_km; + const auto d1 = 10 * km; + const auto d2 = 3 * km; if(d1 / d2 > dimensionless(2)) { // ... } @@ -136,8 +135,8 @@ This is why it was decided to allow the ``dimensionless`` quantity of any representation type to be implicitly constructible from this representation type. With that the above examples can be rewritten as follows:: - const auto d1 = 10_q_km; - const auto d2 = 3_q_km; + const auto d1 = 10 * km; + const auto d2 = 3 * km; if(d1 / d2 > 2) { // ... } @@ -155,8 +154,8 @@ could be ambiguous. For example:: return d1 / d2 + 1; } -As long as we can reason about what such code means for ``foo(10_q_km, 2_q_km)`` it is not that obvious -at all in the case of ``foo(10_q_cm, 2_q_ft)``. To make such code to compile for every case we have to +As long as we can reason about what such code means for ``foo(10 * km, 2 * km)`` it is not that obvious +at all in the case of ``foo(10 * cm, 2 * ft)``. To make such code to compile for every case we have to either change the type of the resulting unit to the one having ``ratio(1)`` (:term:`coherent derived unit`):: Dimensionless auto foo(Length auto d1, Length auto d2) @@ -175,15 +174,15 @@ There is one more important point to note here. As the the dimensionless quantit a number, it is never implicitly converted back to the representation type. This means that the following code will not compile:: - auto v = std::exp(10_q_m / 5_q_m); + auto v = std::exp(10 * m / (5 * m)); To make it compile fine we have to either explicitly get the value stored in the quantity:: - auto v = std::exp(quantity_cast(10_q_m / 5_q_m).number()); + auto v = std::exp(quantity_cast(10 * m / (5 * m)).number()); or use a mathematical wrapper function from `units` namespace:: - auto v = units::exp(10_q_m / 5_q_m); + auto v = units::exp(10 * m / (5 * m)); .. important:: diff --git a/docs/framework/dimensions.rst b/docs/framework/dimensions.rst index 1e9182be..344912a6 100644 --- a/docs/framework/dimensions.rst +++ b/docs/framework/dimensions.rst @@ -20,8 +20,8 @@ each other and the result will always be a quantity of the same dimension: .. code-block:: :emphasize-lines: 3-4 - Length auto dist1 = 2_q_m; - Length auto dist2 = 1_q_m; + Length auto dist1 = 2 * m; + Length auto dist2 = 1 * m; Length auto res1 = dist1 + dist2; Length auto res2 = dist1 - dist2; @@ -32,7 +32,7 @@ not change: .. code-block:: :emphasize-lines: 2-4 - Length auto dist = 2_q_m; + Length auto dist = 2 * m; Length auto res1 = dist * 2; // 4 m Length auto res2 = 3 * res1; // 12 m Length auto res3 = res2 / 2; // 6 m @@ -44,9 +44,9 @@ probably will always end up in a quantity of a yet another dimension: .. code-block:: :emphasize-lines: 4-6 - Length auto dist1 = 2_q_m; - Length auto dist2 = 3_q_m; - Time auto dur1 = 2_q_s; + Length auto dist1 = 2 * m; + Length auto dist2 = 3 * m; + Time auto dur1 = 2 * s; Area auto res1 = dist1 * dist2; // 6 m² Speed auto res2 = dist1 / dur1; // 1 m/s Frequency auto res3 = 10 / dur1; // 5 Hz @@ -58,9 +58,9 @@ dimension, than we will end up with just a dimensionless quantity: .. code-block:: :emphasize-lines: 4-5 - Time auto dur1 = 10_q_s; - Time auto dur2 = 2_q_s; - Frequency auto fr1 = 5_q_Hz; + Time auto dur1 = 10 * s; + Time auto dur2 = 2 * s; + Frequency auto fr1 = 5 * Hz; Dimensionless auto v1 = dur1 / dur2; // quantity(5) Dimensionless auto v2 = dur1 * fr1; // quantity(50) @@ -112,8 +112,8 @@ The result will always be a quantity point of the same dimension: .. code-block:: :emphasize-lines: 3-5 - Length auto dist1 = 2_q_m; - Length auto dist2 = 1_q_m; + Length auto dist1 = 2 * m; + Length auto dist2 = 1 * m; QuantityPoint auto res1 = quantity_point{dist1} + dist2; QuantityPoint auto res2 = dist1 + quantity_point{dist2}; QuantityPoint auto res3 = quantity_point{dist1} - dist2; @@ -124,8 +124,8 @@ The result is a relative quantity of the same dimension: .. code-block:: :emphasize-lines: 3 - Length auto dist1 = 2_q_m; - Length auto dist2 = 1_q_m; + Length auto dist1 = 2 * m; + Length auto dist2 = 1 * m; Length auto res1 = quantity_point{dist1} - quantity_point{dist2}; .. note:: @@ -139,11 +139,11 @@ The result is a relative quantity of the same dimension: .. code-block:: :emphasize-lines: 3-5 - Length auto dist1 = 2_q_m; - Length auto dist2 = 1_q_m; + Length auto dist1 = 2 * m; + Length auto dist2 = 1 * m; auto res1 = quantity_point{dist1} + quantity_point{dist2}; // ERROR auto res2 = dist1 - quantity_point{dist2}; // ERROR - auto res3 = quantity_point{dist1} / 2_q_s; // ERROR + auto res3 = quantity_point{dist1} / (2 * s); // ERROR Quantity Point Kinds ++++++++++++++++++++ diff --git a/docs/framework/quantities.rst b/docs/framework/quantities.rst index 90479df1..a4f0de73 100644 --- a/docs/framework/quantities.rst +++ b/docs/framework/quantities.rst @@ -50,12 +50,44 @@ Thanks to that, the above example can be rewritten as follows:: si::length d(123); si::speed v(70); +Quantity References ++++++++++++++++++++ + +Quantity References provide an alternative and simplified way to create quantities. +They are defined using the `reference` class template:: + + namespace references { + + inline constexpr auto km = reference{}; + inline constexpr auto h = reference{}; + + } + +With the above our code can look as follows:: + + using namespace units::isq::si::references; + auto d = 123. * km; // si::length + auto v = 70 * (km / h); // si::speed + +.. important:: + + The following syntaxes are not allowed: + ``2 / s``, ``km * 3``, ``s / 4``, ``70 * km / h``. + +It is also possible to easily define custom quantity references from existing ones:: + + inline constexpr auto Nm = N * m; + inline constexpr auto km_per_h = km / h; + inline constexpr auto mph = mi / h; + + User Defined Literals +++++++++++++++++++++ + +Alternatively, to construct quantities with compile-time known values the library provides +:abbr:`UDL (User Defined Literal)` s for each :term:`unit` of every :term:`dimension`:: -To further simplify construction of quantities with compile-time known -values the library provides :abbr:`UDL (User Defined Literal)` s for each -:term:`unit` of every :term:`dimension`:: + #if UNITS_UDLS inline namespace literals { @@ -67,8 +99,12 @@ values the library provides :abbr:`UDL (User Defined Literal)` s for each } + #endif // UNITS_UDLS + Thanks to them the same code can be as simple as:: + #define UNITS_UDLS 1 + using namespace units::isq::si::literals; auto d = 123._q_km; // si::length auto v = 70_q_km_per_h; // si::speed @@ -82,37 +118,13 @@ Thanks to them the same code can be as simple as:: ``d`` (day), ``l`` or ``L`` (litre), ``erg``, ``ergps``). This is why the ``_q_`` prefix was consistently applied to all the UDLs. - -Quantity References -+++++++++++++++++++ - -Quantity References provide an alternative way to simplify quantities creation. -They are defined using the `reference` class template:: - - namespace references { - - inline constexpr auto km = reference{}; - inline constexpr auto h = reference{}; - - } - -With the above our code can look as follows:: - - using namespace units::isq::si::references; - auto d = 123. * km; // si::length - auto v = 70 * (km / h); // si::speed - .. important:: - The following syntaxes are not allowed: - ``2 / s``, ``km * 3``, ``s / 4``, ``70 * km / h``. - -It is also allowed to easily define custom quantity references from existing ones:: - - inline constexpr auto Nm = N * m; - inline constexpr auto km_per_h = km / h; - inline constexpr auto mph = mi / h; + As one can read in the next section UDLs, are considered to be inferior to `Quantity References`_ + and their definition affects compile-time performance a lot. This is why they are an opt-in feature + of the library and in order to use them one has to provide a `UNITS_UDL` preprocessor definition. + UDLs vs Quantity References +++++++++++++++++++++++++++ @@ -161,7 +173,10 @@ UDLs are helpful but they also have some disadvantages compared to Quantity Refe auto d1 = 123._q_km; // si::length auto d2 = 123_q_km; // si::length - No possibility to obtain any other representation type. + No possibility to obtain any other representation type. Additionally this gets contagious + as the result of every arithmetic expression on quantities is always expanded to the common + type of its arguments. For example `si::length(1) + 1_q_m` results in a + `si::length` type. - Quantity References:: @@ -183,7 +198,8 @@ UDLs are helpful but they also have some disadvantages compared to Quantity Refe - Quantity References: - one reference per unit - - unnamed derived units constructed from base references (i.e. ``km / h``) + - unnamed derived units are constructed from base references so no explicit + definition is required (i.e. ``km / h``) 5. Typical UDL definition for quantities when compiled with a ``-Wsign-conversion`` flag results in a compilation warning. This warning could be silenced with a @@ -192,6 +208,24 @@ UDLs are helpful but they also have some disadvantages compared to Quantity Refe Quantity References, on the opposite, always use the exact representation type provided by the user so there is no chance for a truncating conversion on a quantity construction. +6. UDLs take long to compile + + - UDLs: + + Every unit requires two UDLs to be defined which in turns requires two instantiations + of "heavy" `quantity` class template. Those are then not often used by non-UDL construction + as most users instantiate `quantity` class template with `int` or `double` which + again have to be separately instantiated. This has a significant impact on the compile-time + performance. + + - Quantity References: + + `reference` class template is "cheaper" to instantiate. Additionally, every unit requires + only one instantiation of a `reference` class template. Such pre-defined reference instance + is then shared among all the instantiations of `quantity` class template for this specific + unit (no matter of its representation type). With this approach we end up with much less class + template instantiations in the application. + Dimension-specific Concepts --------------------------- @@ -200,8 +234,8 @@ In case the user does not care about the specific unit and representation but requires quantity of a concrete dimension than dimension-specific concepts can be used:: - using namespace units::isq::si::literals; - constexpr Length auto d = 123_q_km; // si::length + using namespace units::isq::si::references; + constexpr Length auto d = 123 * km; // si::length .. note:: @@ -215,10 +249,10 @@ assume that the user wants to implement an ``avg_speed`` function that will be calculating the average speed based on provided distance and duration quantities. The usage of such a function can look as follows:: - using namespace units::isq::si::literals; - using namespace units::isq::si::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); + using namespace units::isq::si::references; + using namespace units::isq::si::international::references; + constexpr Speed auto v1 = avg_speed(220 * km, 2 * h); + constexpr Speed auto v2 = avg_speed(140 * mi, 2 * h); In this and all other physical units libraries such a function can be implemented as:: @@ -276,7 +310,7 @@ but often we would like to know a specific type too. We have two options here: - query the actual dimension, unit, and representation types:: - constexpr Speed auto v = avg_speed(220_q_km, 2_q_h); + constexpr Speed auto v = avg_speed(220 * km, 2 * h); using quantity_type = decltype(v); using dimension_type = quantity_type::dimension; using unit_type = quantity_type::unit; @@ -284,7 +318,7 @@ but often we would like to know a specific type too. We have two options here: - convert or cast to a desired quantity type:: - constexpr Speed auto v1 = avg_speed(220._q_km, 2_q_h); + constexpr Speed auto v1 = avg_speed(220. * km, 2 * h); constexpr si::speed v2 = v1; constexpr Speed auto v3 = quantity_cast(v1); @@ -300,8 +334,8 @@ Dimensionless Quantities Whenever we divide two quantities of the same dimension we end up with a :term:`dimensionless quantity` otherwise known as :term:`quantity of dimension one`:: - static_assert(10_q_km / 5_q_km == 2); - static_assert(std::is_same_v>); + static_assert(10 * km / (5 * km) == 2); + static_assert(std::is_same_v>); According to the official ISO definition `dim_one` is a dimension "for which all the exponents of the factors corresponding to the base quantities in its quantity dimension @@ -330,7 +364,7 @@ There are two special units provided for usage with such a quantity: For example the following code:: - std::cout << quantity_cast(50._q_m / 100._q_m) << '\n'; + std::cout << quantity_cast(50. * m / (100. * m)) << '\n'; will print ``50 %`` to the console output. diff --git a/docs/framework/quantity_points.rst b/docs/framework/quantity_points.rst index 4929c68f..9fd23af1 100644 --- a/docs/framework/quantity_points.rst +++ b/docs/framework/quantity_points.rst @@ -14,7 +14,7 @@ Construction To create the quantity point object from a `quantity` we just have to pass the value to the `quantity_point` class template explicit constructor:: - quantity_point d(123_q_km); + quantity_point d(123 * km); .. note:: @@ -25,7 +25,7 @@ the value to the `quantity_point` class template explicit constructor:: `copy initialization `_ **does not compile**:: - quantity_point d = 123_q_km; // ERROR + quantity_point d = 123 * km; // ERROR Differences To Quantity diff --git a/docs/framework/text_output.rst b/docs/framework/text_output.rst index 45c0c54b..c87e8970 100644 --- a/docs/framework/text_output.rst +++ b/docs/framework/text_output.rst @@ -21,10 +21,10 @@ Output Streams The easiest way to print a quantity is to provide its object to the output stream:: - using namespace units::isq::si::literals; - using namespace units::isq::si::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); + using namespace units::isq::si::references; + using namespace units::isq::si::international::references; + constexpr Speed auto v1 = avg_speed(220. * km, 2 * h); + constexpr Speed auto v2 = avg_speed(140. * mi, 2 * h); std::cout << v1 << '\n'; // 110 km/h std::cout << v2 << '\n'; // 70 mi/h @@ -46,9 +46,9 @@ 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| + os << "|" << std::setw(10) << 123 * m << "|"; // | 123 m| + os << "|" << std::setw(10) << std::left << 123 * m << "|"; // |123 m | + os << "|" << std::setw(10) << std::setfill('*') << 123 * m << "|"; // |*****123 m| fmt::format @@ -100,9 +100,9 @@ In case it is left empty the default formatting of ``{:%Q %q}`` is applied. The 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); + std::cout << "Distance: " << 123 * km << "\n"; + fmt::print("Distance: {}\n", 123 * km); + fmt::print("Distance: {:%Q %q}\n", 123 * km); Quantity Value, Symbol, or Both? @@ -111,9 +111,9 @@ 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 + fmt::print("{:%Q}", 123 * km); // 123 + fmt::print("{:%q}", 123 * km); // km + fmt::print("{:%Q%q}", 123 * km); // 123km Controlling Width, Fill, and Alignment @@ -123,14 +123,14 @@ To control width, fill, and alignment the C++ standard grammar tokens ``fill-and 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***| + fmt::print("|{:0}|", 123 * m); // |123 m| + fmt::print("|{:10}|", 123 * m); // | 123 m| + fmt::print("|{:<10}|", 123 * m); // |123 m | + fmt::print("|{:>10}|", 123 * m); // | 123 m| + fmt::print("|{:^10}|", 123 * m); // | 123 m | + fmt::print("|{:*<10}|", 123 * m); // |123 m*****| + fmt::print("|{:*>10}|", 123 * m); // |*****123 m| + fmt::print("|{:*^10}|", 123 * m); // |**123 m***| ASCII-only Quantity Symbols @@ -142,12 +142,13 @@ this by default. From the engineering point of view sometimes Unicode text migh 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 + fmt::print("{}", 10 * R); // 10 Ω + fmt::print("{:%Q %Aq}", 10 * R); // 10 ohm + fmt::print("{}", 125 * us); // 125 µs + fmt::print("{:%Q %Aq}", 125 * us); // 125 us + inline constexpr auto s2 = s * s; + fmt::print("{}", 9.8 * (m / s2)); // 9.8 m/s² + fmt::print("{:%Q %Aq}", 9.8 * (m / s2)); // 9.8 m/s^2 Controlling on How the Quantity Value Is Being Printed @@ -155,8 +156,8 @@ 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 + fmt::print("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", 1 * m); // 1 m,+1 m,1 m, 1 m + fmt::print("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", -1 * m); // -1 m,-1 m,-1 m,-1 m where: @@ -168,47 +169,47 @@ where: ``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 + fmt::print("{:%.0Q %q}", 1.2345 * m); // 1 m + fmt::print("{:%.1Q %q}", 1.2345 * m); // 1.2 m + fmt::print("{:%.2Q %q}", 1.2345 * 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 + fmt::print("{:%bQ %q}", 42 * m); // 101010 m + fmt::print("{:%BQ %q}", 42 * m); // 101010 m + fmt::print("{:%dQ %q}", 42 * m); // 42 m + fmt::print("{:%oQ %q}", 42 * m); // 52 m + fmt::print("{:%xQ %q}", 42 * m); // 2a m + fmt::print("{:%XQ %q}", 42 * 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 + fmt::print("{:%#bQ %q}", 42 * m); // 0b101010 m + fmt::print("{:%#BQ %q}", 42 * m); // 0B101010 m + fmt::print("{:%#oQ %q}", 42 * m); // 052 m + fmt::print("{:%#xQ %q}", 42 * m); // 0x2a m + fmt::print("{:%#XQ %q}", 42 * 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 + fmt::print("{:%aQ %q}", 1.2345678 * m); // 0x9.e065152d8eae841p-3 m + fmt::print("{:%.3aQ %q}", 1.2345678 * m); // 0x9.e06p-3 m + fmt::print("{:%AQ %q}", 1.2345678 * m); // 0X9.E065152D8EAE841P-3 m + fmt::print("{:%.3AQ %q}", 1.2345678 * m); // 0X9.E06P-3 m + fmt::print("{:%eQ %q}", 1.2345678 * m); // 1.234568e+00 m + fmt::print("{:%.3eQ %q}", 1.2345678 * m); // 1.235e+00 m + fmt::print("{:%EQ %q}", 1.2345678 * m); // 1.234568E+00 m + fmt::print("{:%.3EQ %q}", 1.2345678 * m); // 1.235E+00 m + fmt::print("{:%gQ %q}", 1.2345678 * m); // 1.23457 m + fmt::print("{:%gQ %q}", 1.2345678e8 * m); // 1.23457e+08 m + fmt::print("{:%.3gQ %q}", 1.2345678 * m); // 1.23 m + fmt::print("{:%.3gQ %q}", 1.2345678e8 * m); // 1.23e+08 m + fmt::print("{:%GQ %q}", 1.2345678 * m); // 1.23457 m + fmt::print("{:%GQ %q}", 1.2345678e8 * m); // 1.23457E+08 m + fmt::print("{:%.3GQ %q}", 1.2345678 * m); // 1.23 m + fmt::print("{:%.3GQ %q}", 1.2345678e8 * m); // 1.23E+08 m Special Signs @@ -217,7 +218,7 @@ 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 - fmt::print("{:%Q%n%q}", 123_q_km); // 123\nkm - fmt::print("{:%Q%% %q}", 123_q_km); // 123% km + fmt::print("{:%Q_%q}", 123 * km); // 123_km + fmt::print("{:%Q%t%q}", 123 * km); // 123\tkm + fmt::print("{:%Q%n%q}", 123 * km); // 123\nkm + fmt::print("{:%Q%% %q}", 123 * km); // 123% km diff --git a/docs/framework/units.rst b/docs/framework/units.rst index d1449351..847caa66 100644 --- a/docs/framework/units.rst +++ b/docs/framework/units.rst @@ -388,9 +388,9 @@ and user should not instantiate it by him/her-self. However the user can sometim observe this type in case an unit/dimension conversion expression will end up with an unknown/undefined unit type like in the below example:: - using namespace units::isq::si::literals; + using namespace units::isq::si::references; - Length auto l = 100_q_km_per_h * 10_q_s; + Length auto l = 100 * (km / h) * (10 * s); The type of ``l`` above will be ``si::length, long double>``. This is caused diff --git a/docs/use_cases/custom_representation_types.rst b/docs/use_cases/custom_representation_types.rst index 9f561497..fa967452 100644 --- a/docs/use_cases/custom_representation_types.rst +++ b/docs/use_cases/custom_representation_types.rst @@ -92,7 +92,7 @@ representation types we have to obey similar rules:: This also applies when we want to create a quantity with a custom representation type from a regular quantity value:: - Length auto d = 123_q_m; + Length auto d = 123 * m; si::length d1(d); // OK si::length d2(d); // Compile-time error si::length d3(quantity_cast(d)); // OK diff --git a/docs/use_cases/extensions.rst b/docs/use_cases/extensions.rst index bbe92202..7c3f3305 100644 --- a/docs/use_cases/extensions.rst +++ b/docs/use_cases/extensions.rst @@ -130,7 +130,7 @@ coherent unit:: With the above we can now check what is the production rate:: - DeskRate auto rate = quantity_cast(3._d / 20_q_min); + DeskRate auto rate = quantity_cast(3._d / (20 * min)); std::cout << "Desk rate: " << rate << '\n'; // prints 'Desk rate: 9 desk/h' and how much wood is being consumed over a unit of time:: diff --git a/docs/use_cases/interoperability.rst b/docs/use_cases/interoperability.rst index c2877f96..c5cf5fed 100644 --- a/docs/use_cases/interoperability.rst +++ b/docs/use_cases/interoperability.rst @@ -38,9 +38,9 @@ such an explicit conversion:: using namespace std::chrono_literals; - static_assert(quantity{1s} + 1_q_s == 2_q_s); - static_assert(quantity{1s} + 1_q_min == 61_q_s); - static_assert(10_q_m / quantity{2s} == 5_q_m_per_s); + static_assert(quantity{1s} + 1 * s == 2 * s); + static_assert(quantity{1s} + 1 * min == 61 * s); + static_assert(10 * m / quantity{2s} == 5 * (m / s)); .. note:: @@ -63,4 +63,4 @@ provide a deduction guide from `QuantityPointLike`:: using namespace std::chrono_literals; - static_assert(quantity_point{std::chrono::sys_seconds{1s}} + 1_q_s == quantity_point{2s}); + static_assert(quantity_point{std::chrono::sys_seconds{1s}} + 1 * s == quantity_point{2s}); diff --git a/docs/use_cases/linear_algebra.rst b/docs/use_cases/linear_algebra.rst index 0a39299e..4d2d9ae3 100644 --- a/docs/use_cases/linear_algebra.rst +++ b/docs/use_cases/linear_algebra.rst @@ -27,9 +27,9 @@ The official :term:`quantity` definition states: So the most common use case would be to create a vector or matrix of quantities:: - fs_vector, 3> v = { 1_q_m, 2_q_m, 3_q_m }; - fs_vector, 3> u = { 3_q_m, 2_q_m, 1_q_m }; - fs_vector, 3> t = { 3_q_km, 2_q_km, 1_q_km }; + fs_vector, 3> v = { 1 * m, 2 * m, 3 * m }; + fs_vector, 3> u = { 3 * m, 2 * m, 1 * m }; + fs_vector, 3> t = { 3 * km, 2 * km, 1 * km }; Having such definitions we can perform full dimensional analysis operations for the operations allowed by the Linear Algebra rules. For example:: @@ -38,7 +38,7 @@ allowed by the Linear Algebra rules. For example:: std::cout << "v + t = " << v + t << "\n"; std::cout << "t[m] = " << fs_vector, 3>(t) << "\n"; std::cout << "v * u = " << v * u << "\n"; - std::cout << "2_q_m * v = " << 2_q_m * v << "\n"; + std::cout << "2 * m * v = " << 2 * m * v << "\n"; The above code works as expected and produces the following output: @@ -48,7 +48,7 @@ The above code works as expected and produces the following output: v + t = | 3001 m 2002 m 1003 m | t[m] = | 3000 m 2000 m 1000 m | v * u = 10 m² - 2_q_m * v = | 2 m² 4 m² 6 m² | + 2 * m * v = | 2 m² 4 m² 6 m² | Quantities of Linear Algebra Types @@ -79,7 +79,7 @@ output: v + t = | 3001 2002 1003 | m t[m] = | 3000 2000 1000 | m v * u = 10 m² - 2_q_m * v = | 2 4 6 | m² + 2 * m * v = | 2 4 6 | m² .. seealso:: diff --git a/docs/use_cases/unknown_dimensions.rst b/docs/use_cases/unknown_dimensions.rst index da602306..4ef6e262 100644 --- a/docs/use_cases/unknown_dimensions.rst +++ b/docs/use_cases/unknown_dimensions.rst @@ -25,8 +25,9 @@ The same applies to the resulting unit. For example: #include using namespace units::isq::si; + using namespace units::isq::si::references; - constexpr auto result = 144_q_km / 2_q_h; + constexpr auto result = 144 * km / (2 * h); static_assert(std::is_same_v); static_assert(std::is_same_v using namespace units::isq::si; + using namespace units::isq::si::references; - constexpr auto result = 144_q_km / 2_q_h; + constexpr auto result = 144 * km / (2 * h); static_assert(std::is_same_v, exponent>>); static_assert(std::is_same_v