mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 20:34:26 +02:00
docs: Quantity Construction Helpers chapter updated
This commit is contained in:
@@ -28,8 +28,22 @@ the value to the `quantity` class template explicit constructor::
|
|||||||
|
|
||||||
quantity<si::dim_length, si::kilometre, double> d = 123; // ERROR
|
quantity<si::dim_length, si::kilometre, double> d = 123; // ERROR
|
||||||
|
|
||||||
Dimension-Specific Aliases
|
|
||||||
++++++++++++++++++++++++++
|
Quantity Construction Helpers
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
Currently the library provides multiple experimental helpers to instantiate
|
||||||
|
quantities of different dimensions and units. Users are encourages to try them
|
||||||
|
out, vote, and share feedback in this
|
||||||
|
`discussion on GitHub <https://github.com/mpusz/units/discussions/274>`_.
|
||||||
|
|
||||||
|
Most probably only one of the options will be included in the final product so
|
||||||
|
please do not hesitate to vote on the one that suits you the best.
|
||||||
|
|
||||||
|
Dimension-Specific Aliases (Experimental)
|
||||||
|
+++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
To simplify `quantity` objects creation the library provides helper aliases for
|
To simplify `quantity` objects creation the library provides helper aliases for
|
||||||
quantities of each :term:`dimension` which additionally set the representation
|
quantities of each :term:`dimension` which additionally set the representation
|
||||||
@@ -50,8 +64,54 @@ Thanks to that, the above example can be rewritten as follows::
|
|||||||
si::length<si::kilometre> d(123);
|
si::length<si::kilometre> d(123);
|
||||||
si::speed<si::kilometre_per_hour, int> v(70);
|
si::speed<si::kilometre_per_hour, int> v(70);
|
||||||
|
|
||||||
Quantity References
|
Unit-Specific Aliases (Experimental)
|
||||||
+++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
Additionally to the dimension-specific aliases there are also ones provided for
|
||||||
|
each and every :term:`unit` in the library::
|
||||||
|
|
||||||
|
#ifdef UNITS_ALIASES
|
||||||
|
|
||||||
|
namespace units::aliases::isq::si::inline length {
|
||||||
|
|
||||||
|
template<Representation Rep = double> using m = units::isq::si::length<units::isq::si::metre, Rep>;
|
||||||
|
template<Representation Rep = double> using km = units::isq::si::length<units::isq::si::kilometre, Rep>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace units::aliases::isq::si::inline speed {
|
||||||
|
|
||||||
|
template<Representation Rep = double> using m_per_s = units::isq::si::speed<units::isq::si::metre_per_second, Rep>;
|
||||||
|
template<Representation Rep = double> using km_per_h = units::isq::si::speed<units::isq::si::kilometre_per_hour, Rep>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UNITS_ALIASES
|
||||||
|
|
||||||
|
Using the above our code can look as follows::
|
||||||
|
|
||||||
|
using namespace units::aliases::isq;
|
||||||
|
si::length::km<> d(123);
|
||||||
|
si::speed::km_per_h<int> v(70);
|
||||||
|
|
||||||
|
Please note that with the C++20 :abbr:`CTAD (Class Template Argument Deduction)` support
|
||||||
|
for alias templates the above can be rewritten as::
|
||||||
|
|
||||||
|
using namespace units::aliases::isq;
|
||||||
|
si::length::km d(123.);
|
||||||
|
si::speed::km_per_h v(70);
|
||||||
|
|
||||||
|
which will deduce the representation type automatically from the initializer provided
|
||||||
|
by the user.
|
||||||
|
|
||||||
|
Also, this feature allows to be more terse if desired::
|
||||||
|
|
||||||
|
using namespace units::aliases::isq::si;
|
||||||
|
auto d = km(123.);
|
||||||
|
auto v = km_per_h(70);
|
||||||
|
|
||||||
|
Quantity References (Experimental)
|
||||||
|
++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
Quantity References provide an alternative and simplified way to create quantities.
|
Quantity References provide an alternative and simplified way to create quantities.
|
||||||
They are defined using the `reference` class template::
|
They are defined using the `reference` class template::
|
||||||
@@ -91,8 +151,8 @@ It is also possible to easily define custom quantity references from existing on
|
|||||||
inline constexpr auto mph = mi / h;
|
inline constexpr auto mph = mi / h;
|
||||||
|
|
||||||
|
|
||||||
User Defined Literals
|
User Defined Literals (Experimental)
|
||||||
+++++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
Alternatively, to construct quantities with compile-time known values the library provides
|
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`::
|
:abbr:`UDL (User Defined Literal)` s for each :term:`unit` of every :term:`dimension`::
|
||||||
@@ -235,6 +295,184 @@ UDLs are helpful but they also have some disadvantages compared to Quantity Refe
|
|||||||
template instantiations in the application.
|
template instantiations in the application.
|
||||||
|
|
||||||
|
|
||||||
|
Quantity References vs Unit-specific Aliases
|
||||||
|
++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
1. Shadowing issues
|
||||||
|
|
||||||
|
- Quantity References
|
||||||
|
|
||||||
|
References occupy a pool of many short identifiers which sometimes shadow the variables,
|
||||||
|
function arguments, or even template parameters provided by the user or other libraries. This
|
||||||
|
results in warnings being generated by some compilers. The most restrictive here is MSVC which
|
||||||
|
for example emits a warning of shadowing ``N`` template parameter for an array size provided
|
||||||
|
in a header file with Newton unit included via namespace declaration in the ``main()`` program
|
||||||
|
function (see `experimental_angle <https://github.com/mpusz/units/blob/master/example/references/experimental_angle.cpp>`_).
|
||||||
|
In other cases user is forced to rename its local identifiers to not collide with predefined
|
||||||
|
references (see `capacitor_time_curve <https://github.com/mpusz/units/blob/master/example/references/capacitor_time_curve.cpp>`_).
|
||||||
|
|
||||||
|
- Unit-specific Aliases
|
||||||
|
|
||||||
|
As aliases are defined in terms of types rather variables no major shadowing issues were found
|
||||||
|
so far. In case of identifiers abiguity it was always possible to disambiguate with more
|
||||||
|
namespaces prefixed in front of the alias.
|
||||||
|
|
||||||
|
2. Adjustable verbosity
|
||||||
|
|
||||||
|
- Quantity References
|
||||||
|
|
||||||
|
References allow creating custom helpers for complex units. Instead of typing::
|
||||||
|
|
||||||
|
static_assert(2 * km / (2 * (km / h)) == 1 * h);
|
||||||
|
|
||||||
|
one can do the following::
|
||||||
|
|
||||||
|
inline constexpr auto kmph = km / h;
|
||||||
|
static_assert(2 * km / (2 * kmph) == 1 * h);
|
||||||
|
|
||||||
|
- Unit-specific Aliases
|
||||||
|
|
||||||
|
There is no need to create custom helpers for complex units as most of them are predefined in
|
||||||
|
a library already. However, this feature also allows controlling verbosity of the code. For
|
||||||
|
example in the below example ``d1``, ``d2``, and ``d3`` will end up being of the same type
|
||||||
|
and having the same value::
|
||||||
|
|
||||||
|
auto d1 = m(123.45);
|
||||||
|
double a = 123.45;
|
||||||
|
auto d2 = m(a);
|
||||||
|
auto d3 = length::m(a);
|
||||||
|
|
||||||
|
3. Readability
|
||||||
|
|
||||||
|
- Quantity References
|
||||||
|
|
||||||
|
As long as references are easy to understand in the following code::
|
||||||
|
|
||||||
|
auto d = 123 * m;
|
||||||
|
|
||||||
|
it is not that nice when a variable is used instead of a compile time number::
|
||||||
|
|
||||||
|
constexpr Speed auto avg_speed(double d, double t)
|
||||||
|
{
|
||||||
|
using namespace units::isq::si::length_references;
|
||||||
|
using namespace units::isq::si::time_references;
|
||||||
|
return d * m / (t * s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Notice that if ``using namespace units::isq::si::references;`` was used instead above it could
|
||||||
|
cause a clash of ``t`` function parameter with ``si::tonne`` unit symbol if ``si/mass.h`` was
|
||||||
|
included.
|
||||||
|
|
||||||
|
- Unit-specific Aliases
|
||||||
|
|
||||||
|
The same using aliases can look as follows::
|
||||||
|
|
||||||
|
constexpr Speed auto avg_speed(double d, double t)
|
||||||
|
{
|
||||||
|
using namespace units::aliases::isq::si;
|
||||||
|
return m(d) / s(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
or::
|
||||||
|
|
||||||
|
constexpr Speed auto avg_speed(double d, double t)
|
||||||
|
{
|
||||||
|
using namespace units::aliases::isq::si;
|
||||||
|
return length::m(d) / time::s(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
4. Operators Precedence
|
||||||
|
|
||||||
|
- Quantity References
|
||||||
|
|
||||||
|
The syntax for references uses ``*`` operator which has some predefined precedence. This operator
|
||||||
|
always takes a magnitude or a reference as ``lhs`` and a reference as ``rhs``. All other comibnations
|
||||||
|
are not allowed. It means that in order to satisfy the operators precedence sometimes quite a lot
|
||||||
|
of parenthesis have to be sprinkled in the code in order for the code to compile::
|
||||||
|
|
||||||
|
static_assert(2 * km / (2 * (km / h)) == 1 * h);
|
||||||
|
|
||||||
|
- Unit-specific Aliases
|
||||||
|
|
||||||
|
Aliases do not use operator syntax thus they are not affected by the precedence issue.
|
||||||
|
|
||||||
|
5. Composition for unnamed derived units
|
||||||
|
|
||||||
|
- Quantity References
|
||||||
|
|
||||||
|
References have only to be defined for named units. Also for the user's conveniance references are
|
||||||
|
predefined for units raised to a specific power (e.g. ``m2``, ``km3``, etc). All other derived units
|
||||||
|
can be constructed using the provided ones already even if they do not correspond to any predefined
|
||||||
|
dimension::
|
||||||
|
|
||||||
|
inline constexpr auto kmph = km / h;
|
||||||
|
inline constexpr auto kmph3 = kmph * kmph * kmph;
|
||||||
|
|
||||||
|
- Unit-specific Aliases
|
||||||
|
|
||||||
|
Such a feature is not possible with aliases. In order to create a derived unit a full alias template
|
||||||
|
has to be explicitly provided::
|
||||||
|
|
||||||
|
template<Representation Rep = double> using km_per_h = units::isq::si::speed<units::isq::si::kilometre_per_hour, Rep>;
|
||||||
|
|
||||||
|
6. Explicit control over the representation type
|
||||||
|
|
||||||
|
Both options here allow to preserve user provide representation type but only aliases allow
|
||||||
|
to override it if needed.
|
||||||
|
|
||||||
|
7. Simplified quantity casting
|
||||||
|
|
||||||
|
Aliases can easily replace ``quantity_cast<Unit>()`` which is not possible with references::
|
||||||
|
|
||||||
|
constexpr auto meter = 1 * m;
|
||||||
|
std::cout << " = " << quantity_cast<si::international::foot>(meter) << '\n';
|
||||||
|
|
||||||
|
The above code for references may look as follows::
|
||||||
|
|
||||||
|
constexpr auto meter = m(1);
|
||||||
|
std::cout << " = " << international::ft(meter) << '\n';
|
||||||
|
std::cout << " = " << ft(meter) << '\n';
|
||||||
|
|
||||||
|
The above will preserve the representation type of the source type.
|
||||||
|
|
||||||
|
8. Compilation performance
|
||||||
|
|
||||||
|
For our experiments it seems that aliases are 2-5x faster to compile than references (declaring an
|
||||||
|
alias template is much faster than instantiating a class template).
|
||||||
|
|
||||||
|
|
||||||
|
Summary
|
||||||
|
+++++++
|
||||||
|
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Feature | Aliases | References | UDLs |
|
||||||
|
+===============================================+=============+============+===============+
|
||||||
|
| Literals and variables support | **Yes** | **Yes** | Literals only |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Preserves user provided representation type | **Yes** | **Yes** | No |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Explicit control over the representation type | **Yes** | No | No |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Possibility to resolve ambiguity | **Yes** | **Yes** | No |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Readability | **Good** | Medium | **Good** |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Hard to resolve shadowing issues | **No** | Yes | **No** |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Operators precedence issue | **No** | Yes | **No** |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Controlled verbosity | **Yes** | No | No |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Easy composition for derived units | No | **Yes** | No |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Simplified quantity casting | **Yes** | No | No |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Implementation and standardization effort | Medium | **Lowest** | Highest |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
| Compile-time performance | **Fastest** | Medium | Slowest |
|
||||||
|
+-----------------------------------------------+-------------+------------+---------------+
|
||||||
|
|
||||||
|
|
||||||
Dimension-specific Concepts
|
Dimension-specific Concepts
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user