docs: "C++ modules" tabs added to all the code examples

This commit is contained in:
Mateusz Pusz
2024-01-06 08:51:01 +01:00
parent 9611a64ad5
commit 39a66d2c6b
4 changed files with 566 additions and 238 deletions

View File

@@ -2,30 +2,59 @@
Here is a small example of operations possible on scalar quantities:
```cpp
#include <mp-units/systems/si/si.h>
=== "C++ modules"
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
```cpp
import mp_units;
// simple numeric operations
static_assert(10 * km / 2 == 5 * km);
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
// unit conversions
static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m);
// simple numeric operations
static_assert(10 * km / 2 == 5 * km);
// derived quantities
static_assert(1 * km / (1 * s) == 1000 * m / s);
static_assert(2 * km / h * (2 * h) == 4 * km);
static_assert(2 * km / (2 * km / h) == 1 * h);
// unit conversions
static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m);
static_assert(2 * m * (3 * m) == 6 * m2);
// derived quantities
static_assert(1 * km / (1 * s) == 1000 * m / s);
static_assert(2 * km / h * (2 * h) == 4 * km);
static_assert(2 * km / (2 * km / h) == 1 * h);
static_assert(10 * km / (5 * km) == 2 * one);
static_assert(2 * m * (3 * m) == 6 * m2);
static_assert(1000 / (1 * s) == 1 * kHz);
```
static_assert(10 * km / (5 * km) == 2 * one);
static_assert(1000 / (1 * s) == 1 * kHz);
```
=== "Header files"
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
// simple numeric operations
static_assert(10 * km / 2 == 5 * km);
// unit conversions
static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m);
// derived quantities
static_assert(1 * km / (1 * s) == 1000 * m / s);
static_assert(2 * km / h * (2 * h) == 4 * km);
static_assert(2 * km / (2 * km / h) == 1 * h);
static_assert(2 * m * (3 * m) == 6 * m2);
static_assert(10 * km / (5 * km) == 2 * one);
static_assert(1000 / (1 * s) == 1 * kHz);
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/81Ev7qhTd)"
@@ -37,44 +66,83 @@ performed without sacrificing accuracy. Please see the below example for a quick
*[NTTP]: Non-Type Template Parameter
```cpp
#include <mp-units/format.h>
#include <mp-units/ostream.h>
#include <mp-units/systems/international/international.h>
#include <mp-units/systems/isq/isq.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
=== "C++ modules"
using namespace mp_units;
```cpp
#include <iostream>
import mp_units;
constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d,
QuantityOf<isq::time> auto t)
{
return d / t;
}
using namespace mp_units;
int main()
{
using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols;
constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d,
QuantityOf<isq::time> auto t)
{
return d / t;
}
constexpr quantity v1 = 110 * km / h;
constexpr quantity v2 = 70 * mph;
constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h);
constexpr quantity v5 = v3.in(m / s);
constexpr quantity v6 = value_cast<m / s>(v4);
constexpr quantity v7 = value_cast<int>(v6);
int main()
{
using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols;
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
std::cout << std::format("{}", v3) << '\n'; // 110 km/h
std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
std::cout << std::format("{:%Q}", v7) << '\n'; // 31
}
```
constexpr quantity v1 = 110 * km / h;
constexpr quantity v2 = 70 * mph;
constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h);
constexpr quantity v5 = v3.in(m / s);
constexpr quantity v6 = value_cast<m / s>(v4);
constexpr quantity v7 = value_cast<int>(v6);
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
std::cout << std::format("{}", v3) << '\n'; // 110 km/h
std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
std::cout << std::format("{:%Q}", v7) << '\n'; // 31
}
```
=== "Header files"
```cpp
#include <mp-units/format.h>
#include <mp-units/ostream.h>
#include <mp-units/systems/international/international.h>
#include <mp-units/systems/isq/isq.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
using namespace mp_units;
constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d,
QuantityOf<isq::time> auto t)
{
return d / t;
}
int main()
{
using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols;
constexpr quantity v1 = 110 * km / h;
constexpr quantity v2 = 70 * mph;
constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h);
constexpr quantity v5 = v3.in(m / s);
constexpr quantity v6 = value_cast<m / s>(v4);
constexpr quantity v7 = value_cast<int>(v6);
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
std::cout << std::format("{}", v3) << '\n'; // 110 km/h
std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
std::cout << std::format("{:%Q}", v7) << '\n'; // 31
}
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/Tsesa1Pvq)"

View File

@@ -20,13 +20,25 @@ The [SI Brochure](../appendix/references.md#SIBrochure) says:
Following the above, the value of a quantity in the **mp-units** library is created by multiplying
a number with a predefined unit:
```cpp
#include <mp-units/systems/si/si.h>
=== "C++ modules"
using namespace mp_units;
```cpp
import mp_units;
quantity q = 42 * si::metre / si::second;
```
using namespace mp_units;
quantity q = 42 * si::metre / si::second;
```
=== "Header files"
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
quantity q = 42 * si::metre / si::second;
```
!!! info
@@ -34,25 +46,50 @@ quantity q = 42 * si::metre / si::second;
provided by this and other libraries, a quantity can also be created with a two-parameter
constructor:
```cpp
#include <mp-units/systems/si/si.h>
=== "C++ modules"
using namespace mp_units;
```cpp
import mp_units;
quantity q{42, si::metre / si::second};
```
using namespace mp_units;
quantity q{42, si::metre / si::second};
```
=== "Header files"
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
quantity q{42, si::metre / si::second};
```
The above creates an instance of `quantity<derived_unit<si::metre, per<si::second>>{}, int>`.
The same can be obtained using optional unit symbols:
```cpp
#include <mp-units/systems/si/si.h>
=== "C++ modules"
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
```cpp
import mp_units;
quantity q = 42 * m / s;
```
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
quantity q = 42 * m / s;
```
=== "Header files"
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
quantity q = 42 * m / s;
```
!!! tip
@@ -62,14 +99,27 @@ quantity q = 42 * m / s;
Quantities of the same kind can be added, subtracted, and compared to each other:
```cpp
#include <mp-units/systems/si/si.h>
=== "C++ modules"
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
```cpp
import mp_units;
static_assert(1 * km + 50 * m == 1050 * m);
```
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
static_assert(1 * km + 50 * m == 1050 * m);
```
=== "Header files"
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
static_assert(1 * km + 50 * m == 1050 * m);
```
Various quantities can be multiplied or divided by each other:
@@ -96,24 +146,45 @@ Quantity points should be used in all places where adding two values is meaningl
The set of operations that can be done on quantity points is limited compared to quantities.
This introduces an additional type-safety.
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/si/si.h>
#include <mp-units/systems/usc/usc.h>
#include <iostream>
=== "C++ modules"
int main()
{
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
using namespace mp_units::usc::unit_symbols;
```cpp
#include <iostream>
import mp_units;
quantity_point temp{20. * deg_C};
std::cout << "Temperature: "
<< temp.quantity_from_zero() << " ("
<< temp.in(deg_F).quantity_from_zero() << ")\n";
}
```
int main()
{
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
using namespace mp_units::usc::unit_symbols;
quantity_point temp{20. * deg_C};
std::cout << "Temperature: "
<< temp.quantity_from_zero() << " ("
<< temp.in(deg_F).quantity_from_zero() << ")\n";
}
```
=== "Header files"
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/si/si.h>
#include <mp-units/systems/usc/usc.h>
#include <iostream>
int main()
{
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
using namespace mp_units::usc::unit_symbols;
quantity_point temp{20. * deg_C};
std::cout << "Temperature: "
<< temp.quantity_from_zero() << " ("
<< temp.in(deg_F).quantity_from_zero() << ")\n";
}
```
The above outputs:

View File

@@ -38,23 +38,41 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
More requirements for C++ modules support can be found in the
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
=== "C++ modules"
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/si/si.h>
#include <mp-units/systems/usc/usc.h>
#include <iostream>
```cpp
#include <iostream>
import mp_units;
using namespace mp_units;
using namespace mp_units;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
int main()
{
constexpr quantity dist = 364.4 * smoot;
std::cout << "Harvard Bridge length = " << dist << "(" << dist.in(usc::foot) << ", " << dist.in(si::metre) << ") ± 1 εar\n";
}
```
int main()
{
constexpr quantity dist = 364.4 * smoot;
std::cout << "Harvard Bridge length = " << dist << "(" << dist.in(usc::foot) << ", " << dist.in(si::metre) << ") ± 1 εar\n";
}
```
=== "Header files"
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/si/si.h>
#include <mp-units/systems/usc/usc.h>
#include <iostream>
using namespace mp_units;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
int main()
{
constexpr quantity dist = 364.4 * smoot;
std::cout << "Harvard Bridge length = " << dist << "(" << dist.in(usc::foot) << ", " << dist.in(si::metre) << ") ± 1 εar\n";
}
```
Output:

View File

@@ -53,32 +53,62 @@ have shorter type identifiers, resulting in easier-to-understand error messages
Here is a simple example showing how to deal with such quantities:
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
=== "C++ modules"
using namespace mp_units;
```cpp
#include <iostream>
import mp_units;
constexpr quantity<si::metre / si::second> avg_speed(quantity<si::metre> d,
quantity<si::second> t)
{
return d / t;
}
using namespace mp_units;
int main()
{
using namespace mp_units::si::unit_symbols;
constexpr quantity<si::metre / si::second> avg_speed(quantity<si::metre> d,
quantity<si::second> t)
{
return d / t;
}
const quantity distance = 110 * km;
const quantity duration = 2 * h;
const quantity speed = avg_speed(distance, duration);
int main()
{
using namespace mp_units::si::unit_symbols;
std::cout << "A car driving " << distance << " in " << duration
<< " has an average speed of " << speed
<< " (" << speed.in(km / h) << ")\n";
}
```
const quantity distance = 110 * km;
const quantity duration = 2 * h;
const quantity speed = avg_speed(distance, duration);
std::cout << "A car driving " << distance << " in " << duration
<< " has an average speed of " << speed
<< " (" << speed.in(km / h) << ")\n";
}
```
=== "Header files"
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
using namespace mp_units;
constexpr quantity<si::metre / si::second> avg_speed(quantity<si::metre> d,
quantity<si::second> t)
{
return d / t;
}
int main()
{
using namespace mp_units::si::unit_symbols;
const quantity distance = 110 * km;
const quantity duration = 2 * h;
const quantity speed = avg_speed(distance, duration);
std::cout << "A car driving " << distance << " in " << duration
<< " has an average speed of " << speed
<< " (" << speed.in(km / h) << ")\n";
}
```
The code above prints:
@@ -144,38 +174,67 @@ accident.
The previous example can be re-typed using typed quantities in the following way:
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
=== "C++ modules"
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
```cpp
#include <iostream>
import mp_units;
constexpr quantity<isq::speed[m / s]> avg_speed(quantity<isq::length[m]> d,
quantity<isq::time[s]> t)
{
return d / t;
}
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
int main()
{
const quantity distance = isq::distance(110 * km);
const quantity duration = isq::time(2 * h);
const quantity speed = avg_speed(distance, duration);
constexpr quantity<isq::speed[m / s]> avg_speed(quantity<isq::length[m]> d,
quantity<isq::time[s]> t)
{
return d / t;
}
std::cout << "A car driving " << distance << " in " << duration
<< " has an average speed of " << speed
<< " (" << speed.in(km / h) << ")\n";
}
```
int main()
{
const quantity distance = isq::distance(110 * km);
const quantity duration = isq::time(2 * h);
const quantity speed = avg_speed(distance, duration);
std::cout << "A car driving " << distance << " in " << duration
<< " has an average speed of " << speed
<< " (" << speed.in(km / h) << ")\n";
}
```
=== "Header files"
```cpp
#include <mp-units/ostream.h>
#include <mp-units/systems/isq/isq.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
constexpr quantity<isq::speed[m / s]> avg_speed(quantity<isq::length[m]> d,
quantity<isq::time[s]> t)
{
return d / t;
}
int main()
{
const quantity distance = isq::distance(110 * km);
const quantity duration = isq::time(2 * h);
const quantity speed = avg_speed(distance, duration);
std::cout << "A car driving " << distance << " in " << duration
<< " has an average speed of " << speed
<< " (" << speed.in(km / h) << ")\n";
}
```
```text
A car driving 110 km in 2 h has an average speed of 15.2778 m/s (55 km/h)
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/q3PzMzqsh)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/MWxG1j4Pc)"
In case we will accidentally make the same calculation error as before, this time, we will
get a bit longer error message, this time also containing information about the quantity type:
@@ -200,116 +259,228 @@ but there are scenarios where they offer additional level of safety.
Let's see another example:
=== "Simple"
=== "C++ modules"
```cpp hl_lines="42"
#include <mp-units/math.h>
#include <mp-units/systems/si/si.h>
#include <numbers>
=== "Simple"
using namespace mp_units;
```cpp hl_lines="41"
#include <numbers>
import mp_units;
class StorageTank {
quantity<square(si::metre)> base_;
quantity<si::metre> height_;
public:
constexpr StorageTank(const quantity<square(si::metre)>& base,
const quantity<si::metre>& height) :
base_(base), height_(height)
{
}
using namespace mp_units;
// ...
};
class StorageTank {
quantity<square(si::metre)> base_;
quantity<si::metre> height_;
public:
constexpr StorageTank(const quantity<square(si::metre)>& base,
const quantity<si::metre>& height) :
base_(base), height_(height)
{
}
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<si::metre>& radius,
const quantity<si::metre>& height) :
StorageTank(std::numbers::pi * pow<2>(radius), height)
{
}
};
// ...
};
class RectangularStorageTank : public StorageTank {
public:
constexpr RectangularStorageTank(const quantity<si::metre>& length,
const quantity<si::metre>& width,
const quantity<si::metre>& height) :
StorageTank(length * width, height)
{
}
};
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<si::metre>& radius,
const quantity<si::metre>& height) :
StorageTank(std::numbers::pi * pow<2>(radius), height)
{
}
};
int main()
{
using namespace mp_units::si::unit_symbols;
auto tank = RectangularStorageTank(1'000 * mm, 500 * mm, 200 * mm);
// ...
}
```
class RectangularStorageTank : public StorageTank {
public:
constexpr RectangularStorageTank(const quantity<si::metre>& length,
const quantity<si::metre>& width,
const quantity<si::metre>& height) :
StorageTank(length * width, height)
{
}
};
=== "Typed"
int main()
{
using namespace mp_units::si::unit_symbols;
auto tank = RectangularStorageTank(1'000 * mm, 500 * mm, 200 * mm);
// ...
}
```
```cpp hl_lines="53 54 55"
#include <mp-units/math.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si/si.h>
#include <numbers>
=== "Typed"
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
```cpp hl_lines="51 52 53"
#include <numbers>
import mp_units;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
: quantity_spec<isq::length> {} horizontal_length;
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
: quantity_spec<isq::length> {} horizontal_length;
class StorageTank {
quantity<horizontal_area[m2]> base_;
quantity<isq::height[m]> height_;
public:
constexpr StorageTank(const quantity<horizontal_area[m2]>& base,
const quantity<isq::height[m]>& height) :
base_(base), height_(height)
{
}
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
// ...
};
class StorageTank {
quantity<horizontal_area[m2]> base_;
quantity<isq::height[m]> height_;
public:
constexpr StorageTank(const quantity<horizontal_area[m2]>& base,
const quantity<isq::height[m]>& height) :
base_(base), height_(height)
{
}
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<isq::radius[m]>& radius,
const quantity<isq::height[m]>& height) :
StorageTank(quantity_cast<horizontal_area>(std::numbers::pi * pow<2>(radius)),
height)
{
}
};
// ...
};
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) :
StorageTank(length * width, height)
{
}
};
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<isq::radius[m]>& radius,
const quantity<isq::height[m]>& height) :
StorageTank(quantity_cast<horizontal_area>(std::numbers::pi * pow<2>(radius)),
height)
{
}
};
int main()
{
auto tank = RectangularStorageTank(horizontal_length(1'000 * mm),
isq::width(500 * mm),
isq::height(200 * mm));
// ...
}
```
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) :
StorageTank(length * width, height)
{
}
};
int main()
{
auto tank = RectangularStorageTank(horizontal_length(1'000 * mm),
isq::width(500 * mm),
isq::height(200 * mm));
// ...
}
```
=== "Header files"
=== "Simple"
```cpp hl_lines="42"
#include <mp-units/math.h>
#include <mp-units/systems/si/si.h>
#include <numbers>
using namespace mp_units;
class StorageTank {
quantity<square(si::metre)> base_;
quantity<si::metre> height_;
public:
constexpr StorageTank(const quantity<square(si::metre)>& base,
const quantity<si::metre>& height) :
base_(base), height_(height)
{
}
// ...
};
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<si::metre>& radius,
const quantity<si::metre>& height) :
StorageTank(std::numbers::pi * pow<2>(radius), height)
{
}
};
class RectangularStorageTank : public StorageTank {
public:
constexpr RectangularStorageTank(const quantity<si::metre>& length,
const quantity<si::metre>& width,
const quantity<si::metre>& height) :
StorageTank(length * width, height)
{
}
};
int main()
{
using namespace mp_units::si::unit_symbols;
auto tank = RectangularStorageTank(1'000 * mm, 500 * mm, 200 * mm);
// ...
}
```
=== "Typed"
```cpp hl_lines="53 54 55"
#include <mp-units/math.h>
#include <mp-units/systems/isq/isq.h>
#include <mp-units/systems/si/si.h>
#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
: quantity_spec<isq::length> {} horizontal_length;
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[m2]> base_;
quantity<isq::height[m]> height_;
public:
constexpr StorageTank(const quantity<horizontal_area[m2]>& base,
const quantity<isq::height[m]>& height) :
base_(base), height_(height)
{
}
// ...
};
class CylindricalStorageTank : public StorageTank {
public:
constexpr CylindricalStorageTank(const quantity<isq::radius[m]>& radius,
const quantity<isq::height[m]>& height) :
StorageTank(quantity_cast<horizontal_area>(std::numbers::pi * pow<2>(radius)),
height)
{
}
};
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) :
StorageTank(length * width, height)
{
}
};
int main()
{
auto tank = RectangularStorageTank(horizontal_length(1'000 * mm),
isq::width(500 * mm),
isq::height(200 * mm));
// ...
}
```
In the above example, the highlighted call doesn't look that safe anymore in the case
of simple quantities, right? Suppose someone, either by mistake or due to some refactoring,