mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 12:24: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
|
||||
|
||||
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
|
||||
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::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.
|
||||
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;
|
||||
|
||||
|
||||
User Defined Literals
|
||||
+++++++++++++++++++++
|
||||
User Defined Literals (Experimental)
|
||||
++++++++++++++++++++++++++++++++++++
|
||||
|
||||
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`::
|
||||
@@ -235,6 +295,184 @@ UDLs are helpful but they also have some disadvantages compared to Quantity Refe
|
||||
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
|
||||
---------------------------
|
||||
|
||||
|
Reference in New Issue
Block a user