From 39a66d2c6b611c16755e75fd57be39c3a254f8a3 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 6 Jan 2024 08:51:01 +0100 Subject: [PATCH] docs: "C++ modules" tabs added to all the code examples --- docs/getting_started/look_and_feel.md | 168 +++++-- docs/getting_started/quick_start.md | 147 ++++-- docs/index.md | 44 +- .../simple_and_typed_quantities.md | 445 ++++++++++++------ 4 files changed, 566 insertions(+), 238 deletions(-) diff --git a/docs/getting_started/look_and_feel.md b/docs/getting_started/look_and_feel.md index 21e2cee6..581fd1ba 100644 --- a/docs/getting_started/look_and_feel.md +++ b/docs/getting_started/look_and_feel.md @@ -2,30 +2,59 @@ Here is a small example of operations possible on scalar quantities: -```cpp -#include +=== "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 + + 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 -#include -#include -#include -#include -#include +=== "C++ modules" -using namespace mp_units; + ```cpp + #include + import mp_units; -constexpr QuantityOf auto avg_speed(QuantityOf auto d, - QuantityOf 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 auto avg_speed(QuantityOf auto d, + QuantityOf 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(v4); - constexpr quantity v7 = value_cast(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(v4); + constexpr quantity v7 = value_cast(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 + #include + #include + #include + #include + #include + + using namespace mp_units; + + constexpr QuantityOf auto avg_speed(QuantityOf auto d, + QuantityOf 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(v4); + constexpr quantity v7 = value_cast(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)" diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md index 3cb39189..12b9245e 100644 --- a/docs/getting_started/quick_start.md +++ b/docs/getting_started/quick_start.md @@ -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 +=== "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 + + 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 + === "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 + + using namespace mp_units; + + quantity q{42, si::metre / si::second}; + ``` The above creates an instance of `quantity>{}, int>`. The same can be obtained using optional unit symbols: -```cpp -#include +=== "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 + + 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 +=== "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 + + 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 -#include -#include -#include +=== "C++ modules" -int main() -{ - using namespace mp_units; - using namespace mp_units::si::unit_symbols; - using namespace mp_units::usc::unit_symbols; + ```cpp + #include + 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 + #include + #include + #include + + 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: diff --git a/docs/index.md b/docs/index.md index 0150746e..cdb5ae99 100644 --- a/docs/index.md +++ b/docs/index.md @@ -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 -#include -#include -#include + ```cpp + #include + 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 + #include + #include + #include + + 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: diff --git a/docs/users_guide/framework_basics/simple_and_typed_quantities.md b/docs/users_guide/framework_basics/simple_and_typed_quantities.md index 0de6c48a..6c5d01a0 100644 --- a/docs/users_guide/framework_basics/simple_and_typed_quantities.md +++ b/docs/users_guide/framework_basics/simple_and_typed_quantities.md @@ -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 -#include -#include +=== "C++ modules" -using namespace mp_units; + ```cpp + #include + import mp_units; -constexpr quantity avg_speed(quantity d, - quantity t) -{ - return d / t; -} + using namespace mp_units; -int main() -{ - using namespace mp_units::si::unit_symbols; + constexpr quantity avg_speed(quantity d, + quantity 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 + #include + #include + + using namespace mp_units; + + constexpr quantity avg_speed(quantity d, + quantity 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 -#include -#include -#include +=== "C++ modules" -using namespace mp_units; -using namespace mp_units::si::unit_symbols; + ```cpp + #include + import mp_units; -constexpr quantity avg_speed(quantity d, - quantity 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 avg_speed(quantity d, + quantity 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 + #include + #include + #include + + using namespace mp_units; + using namespace mp_units::si::unit_symbols; + + constexpr quantity avg_speed(quantity d, + quantity 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 - #include - #include + === "Simple" - using namespace mp_units; + ```cpp hl_lines="41" + #include + import mp_units; - class StorageTank { - quantity base_; - quantity height_; - public: - constexpr StorageTank(const quantity& base, - const quantity& height) : - base_(base), height_(height) - { - } + using namespace mp_units; - // ... - }; + class StorageTank { + quantity base_; + quantity height_; + public: + constexpr StorageTank(const quantity& base, + const quantity& height) : + base_(base), height_(height) + { + } - class CylindricalStorageTank : public StorageTank { - public: - constexpr CylindricalStorageTank(const quantity& radius, - const quantity& height) : - StorageTank(std::numbers::pi * pow<2>(radius), height) - { - } - }; + // ... + }; - class RectangularStorageTank : public StorageTank { - public: - constexpr RectangularStorageTank(const quantity& length, - const quantity& width, - const quantity& height) : - StorageTank(length * width, height) - { - } - }; + class CylindricalStorageTank : public StorageTank { + public: + constexpr CylindricalStorageTank(const quantity& radius, + const quantity& 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& length, + const quantity& width, + const quantity& 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 - #include - #include - #include + === "Typed" - using namespace mp_units; - using namespace mp_units::si::unit_symbols; + ```cpp hl_lines="51 52 53" + #include + import mp_units; - // add a custom quantity type of kind isq::length - inline constexpr struct horizontal_length - : quantity_spec {} 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 {} horizontal_area; + // add a custom quantity type of kind isq::length + inline constexpr struct horizontal_length + : quantity_spec {} horizontal_length; - class StorageTank { - quantity base_; - quantity height_; - public: - constexpr StorageTank(const quantity& base, - const quantity& 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 {} horizontal_area; - // ... - }; + class StorageTank { + quantity base_; + quantity height_; + public: + constexpr StorageTank(const quantity& base, + const quantity& height) : + base_(base), height_(height) + { + } - class CylindricalStorageTank : public StorageTank { - public: - constexpr CylindricalStorageTank(const quantity& radius, - const quantity& height) : - StorageTank(quantity_cast(std::numbers::pi * pow<2>(radius)), - height) - { - } - }; + // ... + }; - class RectangularStorageTank : public StorageTank { - public: - constexpr RectangularStorageTank(const quantity& length, - const quantity& width, - const quantity& height) : - StorageTank(length * width, height) - { - } - }; + class CylindricalStorageTank : public StorageTank { + public: + constexpr CylindricalStorageTank(const quantity& radius, + const quantity& height) : + StorageTank(quantity_cast(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& length, + const quantity& width, + const quantity& 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 + #include + #include + + using namespace mp_units; + + class StorageTank { + quantity base_; + quantity height_; + public: + constexpr StorageTank(const quantity& base, + const quantity& height) : + base_(base), height_(height) + { + } + + // ... + }; + + class CylindricalStorageTank : public StorageTank { + public: + constexpr CylindricalStorageTank(const quantity& radius, + const quantity& height) : + StorageTank(std::numbers::pi * pow<2>(radius), height) + { + } + }; + + class RectangularStorageTank : public StorageTank { + public: + constexpr RectangularStorageTank(const quantity& length, + const quantity& width, + const quantity& 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 + #include + #include + #include + + 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 {} horizontal_length; + + // add a custom derived quantity type of kind isq::area + // with a constrained quantity equation + inline constexpr struct horizontal_area + : quantity_spec {} horizontal_area; + + class StorageTank { + quantity base_; + quantity height_; + public: + constexpr StorageTank(const quantity& base, + const quantity& height) : + base_(base), height_(height) + { + } + + // ... + }; + + class CylindricalStorageTank : public StorageTank { + public: + constexpr CylindricalStorageTank(const quantity& radius, + const quantity& height) : + StorageTank(quantity_cast(std::numbers::pi * pow<2>(radius)), + height) + { + } + }; + + class RectangularStorageTank : public StorageTank { + public: + constexpr RectangularStorageTank(const quantity& length, + const quantity& width, + const quantity& 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,