# Cheat Sheet This page provides a concise overview of the most common **mp-units** operations and patterns. For detailed explanations, refer to the [Users Guide](../users_guide/framework_basics/interface_introduction.md). ## Setup - **CMake:** `mp-units::mp-units` - **Conan:** `mp-units` === "C++ modules" ```cpp import mp_units; using namespace mp_units; using namespace mp_units::si::unit_symbols; // (1)! ``` 1. The short unit symbols (like `m`, `kg`, `s`, etc.) are not available by default. These short identifiers are too common and may conflict with other code or libraries. This is why they are provided by the `mp_units::si::unit_symbols` namespace, which is opt-in. === "Header files" ```cpp #include #include using namespace mp_units; using namespace mp_units::si::unit_symbols; // (1)! ``` 1. The short unit symbols (like `m`, `kg`, `s`, etc.) are not available by default. These short identifiers are too common and may conflict with other code or libraries. This is why they are provided by the `mp_units::si::unit_symbols` namespace, which is opt-in. ## Quantities ### Simple vs Typed Quantities **mp-units** supports two modes for creating quantities that can be freely mixed: === "Simple Quantities" Focus on **units** and **quantity kinds**. Best for straightforward calculations: ```cpp quantity speed = 60 * km / h; // Unit-based (simple) quantity length = 10 * m; // Simple length ``` - **Pros**: Concise, easier to read, shorter compilation errors - **Use when**: Working with quantities of different kinds or when type safety isn't critical === "Typed Quantities" Add **ISQ quantity types** for stronger type safety: ```cpp quantity speed = isq::speed(60 * km / h); // Typed with ISQ quantity quantity height = isq::height(2 * m); // Different from isq::width or isq::radius quantity width = isq::width(3 * m); // Can't be mixed with height ``` - **Pros**: Prevents accidental mixing of quantities of the same kind (_height_ vs _width_) - **Use when**: Dealing with multiple quantities of the same kind that shouldn't be interchangeable !!! tip "When to use typed quantities" Use typed quantities when you need to distinguish between quantities of the same kind (e.g., _height_ vs _width_ vs _radius_). Otherwise, simple quantities are more concise. ### Creating Quantities The value of the quantity is the product of the **number** and the **unit**: === "Simple Quantities" ```cpp // Basic quantities quantity time = 20 * min; quantity length = 42.f * m; quantity mass = 2.5 * kg; quantity temperature = delta(3); // (1)! // Derived quantities quantity area = 10 * m * 12 * m; quantity speed = 100 * km / (2 * h); // (2)! quantity energy = 0.5 * mass * pow<2>(speed); // (3)! quantity power = energy / time; ``` 1. Temperature is an exception. Its quantities can't be created with the multiply syntax. Use `delta(...)` for temperature differences (relative quantities), and `point(...)` for absolute temperatures. See the [Temperature support](../users_guide/framework_basics/the_affine_space.md#temperature-support) in the User's Guide for details. 2. Parenthesis is required here to result with a proper dimension for a _speed_ quantity. 3. Exponent must be known at compile time to result with a proper quantity type (contrarily to `std::pow`). === "Typed Quantities" ```cpp // Basic ISQ quantities quantity distance = isq::distance(110 * km); quantity duration = isq::duration(2 * h); quantity height = isq::height(10 * m); quantity width = 5 * isq::width[m]; // Derived ISQ quantities quantity speed = isq::speed(distance / duration); quantity area = height * width; // convertible to isq::area ``` ### Quantity Arithmetic Quantity arithmetic affects not only the final value but also its **type**: ```cpp // Basic operations quantity total_length = 10 * m + 5 * m; // 15 m quantity length_diff = 10 * m - 3 * m; // 7 m quantity area = 5 * m * 4 * m; // 20 m² quantity speed = (100 * km) / (2 * h); // 50 km/h // Mixed unit arithmetic quantity total_distance = 1 * km + 500 * m; // 1500 m quantity total_time = 1 * h + 30 * min; // 90 min // Powers and roots quantity volume = pow<3>(2 * m); // 8 m³ quantity side_length = cbrt(27 * m3); // 3 m quantity rms_speed = sqrt(pow<2>(speed)); // Speed magnitude ``` ### ISQ: Quantity Hierarchies and Kinds The International System of Quantities (ISQ) defines **hierarchies of quantities** of the same kind, enabling sophisticated type safety: ```cpp // Quantities of the same kind (length) form a hierarchy quantity w = isq::width(2 * m); quantity h = isq::height(3 * m); quantity l = isq::length(5 * m); // Root of the hierarchy // Implicit conversions UP the hierarchy (specific → general) quantity len1 = w; // ✓ width is a length quantity len2 = h; // ✓ height is a length // Explicit conversions DOWN the hierarchy (general → specific) quantity w2 = isq::width(l); // ✓ Explicit conversion // quantity w3 = l; // ✗ Error: no implicit conversion // Explicit casts for sibling quantities (same level) quantity h2 = quantity_cast(w); // ✓ Forces conversion // quantity h3 = isq::height(w); // ✗ Error: can't convert siblings // Operations result in common quantity type quantity sum = w + h; // Result: isq::length (common parent) ``` !!! note "Preventing incorrect operations" ISQ prevents operations that don't make physical sense: ```cpp // ✗ Can't add quantities of different kinds (even if same dimension) // auto invalid = 1 * Hz + 1 * Bq; // Error: frequency ≠ activity // auto wrong = area + fuel_consumption; // Error: different kinds ``` ### ISQ: Generic Interfaces with `QuantityOf` Use `QuantityOf` concepts to create safe, generic functions that accept any quantity that is convertible to a provided type: ```cpp // Generic function accepting any speed quantity in any unit constexpr QuantityOf auto avg_speed(QuantityOf auto distance, // (1)! QuantityOf auto time) { return distance / time; } quantity v1 = avg_speed(220 * km, 2 * h); // 110 km/h quantity v2 = avg_speed(isq::length(100 * mi), 2 * h); // 50 mi/h quantity v3 = avg_speed(isq::distance(1500 * m), 50 * s); // 30 m/s // quantity v4 = avg_speed(50 * s, 1500 * m); // ✗ Error ``` 1. `QuantityOf` not only documents what the function returns, but also serves as a compile-time unit test verifying that the quantity equation implemented in the function returns a correct quantity type. ### ISQ: Defining Custom Quantities Create your own quantity types to extend ISQ hierarchies: ```cpp // Define a custom quantity in the length hierarchy inline constexpr struct horizontal_length final : quantity_spec {} horizontal_length; // Define a derived quantity with a constrained equation inline constexpr struct horizontal_area final : quantity_spec {} horizontal_area; // Use custom quantities for stronger type safety quantity base_length = horizontal_length(100 * m); quantity base_width = isq::width(50 * m); quantity base_area = base_length * base_width; // ✓ OK // quantity wrong = isq::height(3 * m) * base_width; // ✗ Error ``` ### Quantity Points ```cpp // Time points (absolute time) inline constexpr struct epoch final : absolute_point_origin> {} epoch; quantity_point later = epoch + 3600 * s; // 1 hour later quantity duration = later - epoch; // 3600 s // Temperature points (absolute temperatures) quantity_point temp_point = point(20); // Absolute temperature quantity_point temp_kelvin = temp_point.in(K); // 293.15 K // Temperature differences (relative quantities) quantity temp_diff = delta(10); // Temperature difference quantity_point new_temp = temp_point + temp_diff; // 30 °C ``` ### Dimensionless Quantities ```cpp // Counts, ratios, and efficiencies quantity count = 42 * one; // 42 quantity amount = 23 * percent; // 23 % quantity efficiency = 850. * W / (1000. * W); // 0.85 quantity ratio = (5. * km) / (2. * m); // 2.5 km/m // Angular quantities quantity angle_deg = 90. * deg; // Angle in degrees quantity angle_rad = angle_deg.in(rad); // π/2 rad quantity sin_value = si::sin(angle_rad); // 1.0 ``` ## Units ### Defining Units ```cpp inline constexpr struct second final : named_unit<"s", kind_of> {} second; inline constexpr struct metre final : named_unit<"m", kind_of> {} metre; inline constexpr struct gram final : named_unit<"g", kind_of> {} gram; inline constexpr auto kilogram = si::kilo; inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton; inline constexpr struct bar final : named_unit<"bar", mag<100> * kPa> {} bar; inline constexpr struct yard final : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard; inline constexpr struct dalton final : named_unit<"Da", mag_ratio<16'605'390'666'050, 10'000'000'000'000> * mag_power<10, -27> * kg> {} dalton; ``` ### Working with Units ```cpp // "importing" specific unit symbols using mp_units::si::unit_symbols::kg; // User-defined aliases for SI units constexpr Unit auto m = si::metre; constexpr Unit auto km = si::kilo; constexpr Unit auto h = non_si::hour; // (1)! // Derived units constexpr Unit auto m2 = square(m); constexpr Unit auto m3 = cubic(si::metre); constexpr Unit auto mps = m / s; // Constants as a unit constexpr Unit auto two_pi = mag<2> * π; ``` 1. Non-SI unit accepted for use with SI ### Unit Conversions ```cpp // Explicit conversions quantity distance = (5 * km).in(m); // 5000 m quantity speed = (60 * km / h).force_in(m / s); // 16 m/s (1) quantity temp = delta(3).in(deg_F); // 5.4 ℉ quantity pressure = (101325. * Pa).in(bar); // 1.01325 bar // Value extraction int distance_value = (42 * m).numerical_value_in(m); // 42 double speed_value = (100 * km / h).force_numerical_value_in(m / s); // 27 (2) ``` 1. Potential value truncation. 2. Potential value truncation. ## Output & Formatting === "C++20" ```cpp #include #include // Basic formatting std::cout << std::format("{}\n", 42 * m); // 42 m std::cout << std::format("{:%N in %U of %D}\n", 42 * m); // 42 in m of L std::cout << std::format("{}\n", 3.14159 * m); // 3.14159 m std::cout << std::format("{::N[.2f]}\n", 3.14159 * m); // 3.14 m // Unit symbols std::cout << std::format("{}\n", 42 * kΩ); // 42 kΩ std::cout << std::format("{::U[P]}\n", 42 * kΩ); // 42 kohm std::cout << std::format("{:%U}\n", 42 * kΩ); // kΩ // Derived units std::cout << std::format("{}\n", 9.81 * m / s2); // 9.81 m/s² std::cout << std::format("{::U[P]}\n", 9.81 * m / s2); // 9.81 m/s^2 std::cout << std::format("{::U[n]}\n", 9.81 * m / s2); // 9.81 m s⁻² ``` === "C++23" ```cpp #include // Basic formatting std::println("{}", 42 * m); // 42 m std::println("{:%N in %U of %D}", 42 * m); // 42 in m of L std::println("{}", 3.14159 * m); // 3.14159 m std::println("{::N[.2f]}", 3.14159 * m); // 3.14 m // Unit symbols std::println("{}", 42 * kΩ); // 42 kΩ std::println("{::U[P]}", 42 * kΩ); // 42 kohm std::println("{:%U}", 42 * kΩ); // kΩ // Derived units std::println("{}", 9.81 * m / s2); // 9.81 m/s² std::println("{::U[P]}", 9.81 * m / s2); // 9.81 m/s^2 std::println("{::U[n]}", 9.81 * m / s2); // 9.81 m s⁻² ``` ## Compile-Time Safety === "Representation Safety" Prevents lossy conversions that would truncate or lose precision: ```cpp quantity distance = (5 * km).in(m); // ✓ 5000 m (widening) quantity height = (186. * cm).in(m); // ✓ 1.86 m (floating-point) quantity length = (short{2} * m).in(mm); // ✓ 2000 mm (explicit) quantity duration = (90 * min).force_in(h); // ✓ 1 h (forced, may truncate) // quantity wrong = (42 * m).in(km); // ✗ Error: truncating int conversion // quantity overflow = (std::int8_t{1} * m).in(mm); // ✗ Error: only 0 preserves the value // quantity bad = (1.5 * m).in(); // ✗ Error: double → int needs explicit cast // quantity invalid = 1.5 * m; // ✗ Error: double → int needs explicit cast ``` === "Affine Space Safety" Distinguishes absolute points from relative differences (vectors): ```cpp quantity temp_diff = delta(3) + delta(2); // ✓ 5 °C (diff + diff = diff) quantity_point temp = point(20) + delta(3); // ✓ 23 °C (point + diff = point) quantity diff = point(25) - point(20); // ✓ 5 °C (point - point = diff) // auto illegal = point(18) + point(10); // ✗ Error: can't add two points // auto wrong = delta(5) - point(20); // ✗ Error: can't subtract point from diff ``` === "Dimension Safety" Ensures operations are dimensionally consistent: ```cpp quantity energy = 0.5 * mass * pow<2>(speed); // ✓ kg⋅m²/s² (energy dimension) quantity force = mass * si::standard_gravity; // ✓ kg⋅m/s² (force dimension) quantity sum = 100 * m + 50 * m; // ✓ 150 m (same dimension) // quantity invalid = 2 * kg; // ✗ Error: mass ≠ length // quantity wrong = 10 * m + 5 * s; // ✗ Error: length + time // quantity bad = si::sin(42 * m); // ✗ Error: sin requires dimensionless angular quantity ``` === "Quantity Kind Safety" Prevents mixing quantities of different kinds even with the same dimension: ```cpp quantity angle1 = 2 * rad + 4 * rad; // ✓ 6 rad (plane angle) quantity solid1 = 3 * sr + 5 * sr; // ✓ 8 sr (solid angle) quantity freq = 50 * Hz + 10 * Hz; // ✓ 60 Hz (frequency) quantity activity = 100 * Bq + 50 * Bq; // ✓ 150 Bq (radioactive activity) // quantity wrong1 = 1 * rad + 1 * sr; // ✗ Error: plane angle ≠ solid angle // quantity wrong2 = 1 * Hz + 1 * Bq; // ✗ Error: frequency ≠ activity ``` === "Quantity Type Safety" Distinguishes between different quantities of the same kind using ISQ: ```cpp // Different quantities of the same kind (length) quantity width = isq::width(2 * m); quantity height = isq::height(3 * m); // ✓ Implicit conversions to common parent (specific → general) quantity length = width; // ✓ width is a length // ✓ Operations find common quantity type quantity sum = width + height; // ✓ Result: isq::length quantity area = width * height; // ✓ width × height → area quantity vol = area * height; // ✓ area × height → volume // Different quantities of the same kind (energy) quantity Ek = isq::kinetic_energy(250 * J); // ✓ Kinetic energy quantity Ep = isq::potential_energy(500 * J); // ✓ Potential energy quantity Em = Ek + Ep; // ✓ Result: mechanical energy // ✗ No implicit conversions between siblings or downward // quantity width2 = height; // ✗ Error: height → width (siblings) // quantity height2 = length; // ✗ Error: length → height (general → specific) // quantity Ek2 = Ep; // ✗ Error: potential → kinetic (siblings) // Use explicit conversion when you know it's safe quantity q = quantity_cast(width); // ✓ Explicit cast ``` !!! note "All safety checks are compile-time errors" Every commented-out line marked with `✗ Error` in the examples above will produce a **compile-time error** if uncommented. The library catches these mistakes during compilation, not at runtime. ## Learn More - **Getting Started**: [Introduction](../getting_started/introduction.md) and [Installation](../getting_started/installation_and_usage.md) - **Simple vs Typed**: [Simple and Typed Quantities](../users_guide/framework_basics/simple_and_typed_quantities.md) - **ISQ Deep Dive**: [ISQ Blog Series](../blog/posts/isq-part-1-introduction.md) - Understanding quantity hierarchies and kinds - **Examples**: [Hello Units](../examples/hello_units.md) and [Average Speed](../examples/avg_speed.md) - **FAQ**: [Frequently Asked Questions](../getting_started/faq.md)