docs: improved the docs for using-directives of unit_symbols

This commit is contained in:
Mateusz Pusz
2024-02-27 09:43:41 +01:00
parent d9723b61a6
commit 63d00977e1
3 changed files with 94 additions and 48 deletions

View File

@@ -95,39 +95,86 @@ The same can be obtained using optional unit symbols:
Unit symbols introduce a lot of short identifiers into the current scope, which may cause
naming collisions with unrelated but already existing identifiers in the code base.
This is why unit symbols are opt-in.
This is why unit symbols are opt-in and typically should be imported only in the context
where they are being used (e.g., function scope).
A user has several options here to choose from depending on the required scenario and possible
naming conflicts:
- explicitly "import" all of them from a dedicated `unit_symbols` namespace with a
[using-directive](https://en.cppreference.com/w/cpp/language/namespace#Using-directives):
=== "using-directive"
Explicitly "import" all of the symbols of a specific system of units from a dedicated
`unit_symbols` namespace with a
[using-directive](https://en.cppreference.com/w/cpp/language/namespace#Using-directives):
```cpp
using namespace mp_units;
using namespace mp_units::si::unit_symbols; // imports all the SI symbols at once
quantity q = 42 * m / s;
void foo(double speed_m_s)
{
// imports all the SI symbols at once
using namespace si::unit_symbols;
quantity speed = speed_m_s * m / s;
// ...
}
```
- selectively select only the required and not-conflicting ones with
[using-declarations](https://en.cppreference.com/w/cpp/language/using_declaration):
!!! note
This solution is perfect for small and isolated scopes but can cause surprising issues
when used in larger scopes or when used for the entire program namespace.
There are 29 named units in SI, and each of them has many prefixed variations (e.g.,
`ng`, `kcd`, ...). It is pretty easy to introduce a name collision with those.
=== "using-declaration"
Selectively bring only the required and not-conflicting symbols with
[using-declarations](https://en.cppreference.com/w/cpp/language/using_declaration):
```cpp
using namespace mp_units;
using si::unit_symbols::m;
using si::unit_symbols::s;
quantity q = 42 * m / s;
void foo(double N)
{
// 'N' function parameter would collide with the SI symbol for Newton, so we only bring what we need
using si::unit_symbols::m;
using si::unit_symbols::s;
quantity speed = N * m / s;
// ...
}
```
- specify a custom not conflicting unit identifier for a unit:
=== "custom short identifier"
Specify a custom not conflicting unit identifier for a unit:
```cpp
using namespace mp_units;
constexpr Unit auto mps = si::metre / si::second;
quantity q = 42 * mps;
void foo(double speed_m_s)
{
// names of some local variables are conflicting with the symbols we want to use
auto m = ...;
auto s = ...;
constexpr Unit auto mps = si::metre / si::second;
quantity speed = speed_m_s * mps;
}
```
=== "unit names"
Full unit names are straightforward to use and often provide the most readable code:
```cpp
using namespace mp_units;
void foo(double m, double s)
{
quantity speed = m * si::metre / (s * si::second);
// ...
}
```
Quantities of the same kind can be added, subtracted, and compared to each other:

View File

@@ -179,16 +179,17 @@ The previous example can be re-typed using typed quantities in the following way
import mp_units;
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
constexpr quantity<isq::speed[m / s]> avg_speed(quantity<isq::length[m]> dist,
quantity<isq::time[s]> time)
constexpr quantity<isq::speed[si::metre / si::second]> avg_speed(quantity<isq::length[si::metre]> dist,
quantity<isq::time[si::second]> time)
{
return dist / time;
}
int main()
{
using namespace mp_units::si::unit_symbols;
const quantity distance = isq::distance(110 * km);
const quantity duration = isq::time(2 * h);
const quantity speed = avg_speed(distance, duration);
@@ -207,16 +208,17 @@ The previous example can be re-typed using typed quantities in the following way
#include <print>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
constexpr quantity<isq::speed[m / s]> avg_speed(quantity<isq::length[m]> dist,
quantity<isq::time[s]> time)
constexpr quantity<isq::speed[si::metre / si::second]> avg_speed(quantity<isq::length[si::metre]> dist,
quantity<isq::time[si::second]> time)
{
return dist / time;
}
int main()
{
using namespace mp_units::si::unit_symbols;
const quantity distance = isq::distance(110 * km);
const quantity duration = isq::time(2 * h);
const quantity speed = avg_speed(distance, duration);
@@ -312,7 +314,6 @@ Let's see another example:
import mp_units;
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
@@ -324,11 +325,11 @@ Let's see another example:
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[m2]> base_;
quantity<isq::height[m]> height_;
quantity<horizontal_area[square(si::metre)]> base_;
quantity<isq::height[si::metre]> height_;
public:
constexpr StorageTank(const quantity<horizontal_area[m2]>& base,
const quantity<isq::height[m]>& height) :
constexpr StorageTank(const quantity<horizontal_area[square(si::metre)]>& base,
const quantity<isq::height[si::metre]>& height) :
base_(base), height_(height)
{
}
@@ -338,8 +339,8 @@ Let's see another example:
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<isq::radius[m]>& radius,
const quantity<isq::height[m]>& height) :
constexpr CylindricalStorageTank(const quantity<isq::radius[si::metre]>& radius,
const quantity<isq::height[si::metre]>& height) :
StorageTank(quantity_cast<horizontal_area>(std::numbers::pi * pow<2>(radius)),
height)
{
@@ -348,9 +349,9 @@ Let's see another example:
class RectangularStorageTank : public StorageTank {
public:
constexpr RectangularStorageTank(const quantity<horizontal_length[m]>& length,
const quantity<isq::width[m]>& width,
const quantity<isq::height[m]>& height) :
constexpr RectangularStorageTank(const quantity<horizontal_length[si::metre]>& length,
const quantity<isq::width[si::metre]>& width,
const quantity<isq::height[si::metre]>& height) :
StorageTank(length * width, height)
{
}
@@ -358,6 +359,7 @@ Let's see another example:
int main()
{
using namespace mp_units::si::unit_symbols;
auto tank = RectangularStorageTank(horizontal_length(1'000 * mm),
isq::width(500 * mm),
isq::height(200 * mm));
@@ -425,7 +427,6 @@ Let's see another example:
#include <numbers>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
@@ -437,11 +438,11 @@ Let's see another example:
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[m2]> base_;
quantity<isq::height[m]> height_;
quantity<horizontal_area[square(si::metre)]> base_;
quantity<isq::height[si::metre]> height_;
public:
constexpr StorageTank(const quantity<horizontal_area[m2]>& base,
const quantity<isq::height[m]>& height) :
constexpr StorageTank(const quantity<horizontal_area[square(si::metre)]>& base,
const quantity<isq::height[si::metre]>& height) :
base_(base), height_(height)
{
}
@@ -451,8 +452,8 @@ Let's see another example:
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<isq::radius[m]>& radius,
const quantity<isq::height[m]>& height) :
constexpr CylindricalStorageTank(const quantity<isq::radius[si::metre]>& radius,
const quantity<isq::height[si::metre]>& height) :
StorageTank(quantity_cast<horizontal_area>(std::numbers::pi * pow<2>(radius)),
height)
{
@@ -461,9 +462,9 @@ Let's see another example:
class RectangularStorageTank : public StorageTank {
public:
constexpr RectangularStorageTank(const quantity<horizontal_length[m]>& length,
const quantity<isq::width[m]>& width,
const quantity<isq::height[m]>& height) :
constexpr RectangularStorageTank(const quantity<horizontal_length[si::metre]>& length,
const quantity<isq::width[si::metre]>& width,
const quantity<isq::height[si::metre]>& height) :
StorageTank(length * width, height)
{
}
@@ -471,6 +472,7 @@ Let's see another example:
int main()
{
using namespace mp_units::si::unit_symbols;
auto tank = RectangularStorageTank(horizontal_length(1'000 * mm),
isq::width(500 * mm),
isq::height(200 * mm));

View File

@@ -100,9 +100,6 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
using Price = quantity_point<currency[us_dollar]>;
using Scaled = quantity_point<currency[scaled_us_dollar], zeroth_point_origin<currency>, std::int64_t>;
Price price{12.95 * USD};
Scaled spx = value_cast<USD_s, std::int64_t>(price);
```
=== "C++20"
@@ -123,9 +120,6 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
using Price = quantity_point<currency[us_dollar]>;
using Scaled = quantity_point<currency[scaled_us_dollar], zeroth_point_origin<currency>, std::int64_t>;
Price price{12.95 * USD};
Scaled spx = value_cast<USD_s, std::int64_t>(price);
```
=== "Portable"
@@ -146,7 +140,10 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
using Price = quantity_point<currency[us_dollar]>;
using Scaled = quantity_point<currency[scaled_us_dollar], zeroth_point_origin<currency>, std::int64_t>;
Price price{12.95 * USD};
Scaled spx = value_cast<USD_s, std::int64_t>(price);
```
```cpp
using namespace unit_symbols;
Price price{12.95 * USD};
Scaled spx = value_cast<USD_s, std::int64_t>(price);
```