### Serve Documentation Locally Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Start a live server to preview the documentation as you write. This command requires Material for MkDocs to be installed. ```shell mkdocs serve ``` -------------------------------- ### Install Documentation Dependencies Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Install the necessary Python packages for building mp-units documentation using Material for MkDocs. ```shell pip install -U mkdocs-material mkdocs-rss-plugin ``` -------------------------------- ### Install Ubuntu Packages for API Reference Generation Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Installs essential LaTeX and Haskell development tools required for generating API reference documents on Ubuntu. ```bash sudo apt install latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended lmodern sudo apt install haskell-stack graphviz nodejs npm ghc cabal-install ``` -------------------------------- ### Include Headers for SI Constants Example Source: https://github.com/mpusz/mp-units/blob/master/docs/examples/si_constants.md Includes necessary header files for the SI constants example. Ensure all required headers are present before using the constants. ```cpp #include #include #include "mp_units/physical_constants/si.h" #include "mp_units/quantity.h" #include "mp_units/unit.h" ``` -------------------------------- ### Example Usage of add_example Function Source: https://github.com/mpusz/mp-units/blob/master/example/CMakeLists.txt These lines demonstrate the invocation of the `add_example` function for various example projects. Each call specifies the target name and optionally other dependencies. ```cmake add_example(avg_speed) ``` ```cmake add_example(capacitor_time_curve) ``` ```cmake add_example(currency) ``` ```cmake add_example(foot_pound_second) ``` ```cmake add_example(glide_computer glide_computer_lib) ``` ```cmake add_example(hello_units) ``` ```cmake add_example(hw_voltage) ``` ```cmake add_example(measurement example_utils) ``` ```cmake add_example(si_constants) ``` ```cmake add_example(spectroscopy_units) ``` ```cmake add_example(storage_tank) ``` ```cmake add_example(strong_angular_quantities) ``` ```cmake add_example(total_energy) ``` ```cmake add_example(unmanned_aerial_vehicle example_utils) ``` -------------------------------- ### Build Documentation Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Build the static documentation site for mp-units. This command requires Material for MkDocs to be installed. ```shell mkdocs build ``` -------------------------------- ### Install Node.js Packages for API Reference Generation Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Installs JavaScript packages needed for API reference generation, including MathJax for typesetting mathematical formulas. ```bash npm install split mathjax-full mathjax-node-sre mathjax-node-cli yargs@16.2.0 ``` -------------------------------- ### Run API Reference Script (Setup Only) Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Executes the automated script in setup-only mode, which configures CMake without building the documentation. ```bash .devcontainer/api_reference.sh -s ``` -------------------------------- ### Explicit Quantity Initialization Example Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.3.0-released.md Shows the correct syntax for creating a `quantity` using the `delta` helper, which is appropriate for temperature differences or when the origin is not specified. ```cpp quantity Temperature = delta(28.0); ``` ```cpp auto Temperature = delta(28.0); ``` -------------------------------- ### Example Usage of Strongly Typed Quantities Source: https://github.com/mpusz/mp-units/blob/master/docs/workshops/advanced/strongly_typed_counts.md Demonstrates the usage of custom quantity types for screen dimensions, sprite position, and rendering statistics. Includes validation and calculation examples. ```cpp int main() { using namespace si::unit_symbols; // Screen configuration quantity screen_width = resolution_width(1920); quantity screen_height = resolution_height(1080); // Sprite position quantity pos_x = pixel_x(100); quantity pos_y = pixel_y(50); // Rendering stats quantity rendered = sprite_count(1500); quantity target_fps = 60.0 / s; quantity frame_time = 1.0 / target_fps; // Validate position if (is_within_bounds(pos_x, pos_y, screen_width, screen_height)) std::cout << "Position (" << pos_x << ", " << pos_y << ") is valid\n"; // Calculate buffer index quantity index = grid_index(pos_x, pos_y, screen_width); std::cout << "Buffer index: " << index << "\n"; // Calculate render rate quantity rate = render_rate_calc(rendered, frame_time); std::cout << "Render rate: " << rate << "\n"; } ``` -------------------------------- ### C++ Quotient-Remainder Theorem Example Source: https://github.com/mpusz/mp-units/blob/master/docs/users_guide/framework_basics/quantity_arithmetics.md Illustrates the C++ quotient-remainder theorem with integral types, showing how truncation can affect modulo results. ```cpp auto q = 5 * h % (120 * min); ``` ```text q = a / b; r = a % b; q * b + r == a; ``` ```cpp const quantity a = 5 * h; const quantity b = 120 * min; const quantity q = a / b; const quantity r = a - q * b; std::cout << "reminder: " << r << "\n"; ``` ```text reminder: 5 h ``` -------------------------------- ### Add Example Executable Target Source: https://github.com/mpusz/mp-units/blob/master/example/CMakeLists.txt This CMake function, `add_example`, is used to define executables for examples. It handles both C++ module and header-only builds, including linking and optional compile options for tracing. ```cmake function(add_example target) if(MP_UNITS_BUILD_CXX_MODULES) add_executable(${target} ${target}.cpp) target_compile_features(${target} PRIVATE cxx_std_20) target_compile_definitions(${target} PRIVATE MP_UNITS_MODULES) target_link_libraries(${target} PRIVATE mp-units::mp-units ${ARGN}) if(MP_UNITS_DEV_TIME_TRACE STREQUAL "MODULES") target_compile_options(${target} PRIVATE "-ftime-trace") endif() endif() add_executable(${target}-headers ${target}.cpp) list(TRANSFORM ARGN APPEND "-headers") target_link_libraries(${target}-headers PRIVATE mp-units::mp-units ${ARGN}) if(MP_UNITS_DEV_TIME_TRACE STREQUAL "HEADERS") target_compile_options(${target}-headers PRIVATE "-ftime-trace") endif() endfunction() ``` -------------------------------- ### Install mp-units with Conan and CMake Source: https://github.com/mpusz/mp-units/blob/master/docs/getting_started/installation_and_usage.md Install the mp-units library on your file system using Conan and CMake. This allows other repositories to find and use the library via `find_package(mp-units)`. ```shell conan install . -pr -s compiler.cppstd=20 -b=missing mv CMakeUserPresets.json src cd src cmake --preset conan-default -DCMAKE_INSTALL_PREFIX= cmake --build --preset conan-release --target install ``` -------------------------------- ### Conan install with auto option (deprecated) Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.3.0-released.md Example of how to install Conan packages using the 'auto' option, which has been removed in newer versions. This syntax is no longer supported. ```bash conan install . -o 'mp-units:std_format=auto' -s compiler.cppstd=23 -b missing ``` -------------------------------- ### Conan install with explicit option value Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.3.0-released.md Example of how to install Conan packages by explicitly setting an option to 'True' or 'False', overriding the automatic deduction. This is used when a specific configuration is required. ```bash conan install . -o 'mp-units:std_format=True' -s compiler.cppstd=23 -b missing ``` -------------------------------- ### Preview Documentation Locally Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Use this command to serve the documentation locally, allowing you to preview changes before deploying them. This command starts a local web server. ```bash # Preview documentation locally mkdocs serve ``` -------------------------------- ### Conan install skipping auto option Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.3.0-released.md Example of how to install Conan packages by skipping an option that was previously set to 'auto'. This allows the library to automatically determine the value during the configuration stage. ```bash conan install . -s compiler.cppstd=23 -b missing ``` -------------------------------- ### Set up CMake Project Source: https://github.com/mpusz/mp-units/blob/master/test_package/CMakeLists.txt Initializes the CMake build system for the project. Specifies the minimum required version and the project name. ```cmake cmake_minimum_required(VERSION 3.30.5) project(test_package LANGUAGES CXX) ``` -------------------------------- ### Run API Reference Script (Setup Only) with Custom Dependency Directory Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Combines setup-only mode with a custom dependency directory using the -s and -d parameters. ```bash .devcontainer/api_reference.sh -s -d ./local_deps ``` -------------------------------- ### Main Function with Simple Quantities Example Source: https://github.com/mpusz/mp-units/blob/master/docs/users_guide/framework_basics/simple_and_typed_quantities.md Demonstrates creating a 'RectangularStorageTank' using simple quantities. Values like '1000 * mm' are passed directly without explicit type definitions for dimensions. ```cpp int main() { using namespace mp_units::si::unit_symbols; auto tank = RectangularStorageTank(1'000 * mm, 500 * mm, 200 * mm); // ... } ``` -------------------------------- ### Export Targets and Configure Package Source: https://github.com/mpusz/mp-units/blob/master/src/CMakeLists.txt Exports targets for external use and configures the package configuration file when installation is enabled. This is part of the local build setup. ```cmake if(MP_UNITS_BUILD_INSTALL) # local build export(EXPORT mp-unitsTargets NAMESPACE mp-units::) configure_file(mp-unitsConfig.cmake.in mp-unitsConfig.cmake @ONLY) include(CMakePackageConfigHelpers) write_basic_package_version_file(mp-unitsConfigVersion.cmake COMPATIBILITY SameMajorVersion) configure_file(cmake/import-std-setup.cmake import-std-setup.cmake COPYONLY) # installation install(EXPORT mp-unitsTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mp-units NAMESPACE mp-units::) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mp-unitsConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/mp-unitsConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/import-std-setup.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mp-units ) endif() ``` -------------------------------- ### Update documentation chapters Source: https://github.com/mpusz/mp-units/blob/master/docs/release_notes.md Updates several documentation chapters, including 'Getting Started', 'Basic Concepts', and 'Interface Introduction'. Also adds a new 'Design Overview' chapter and reworks the 'Concepts' chapter. ```markdown docs: "Getting Started" chapters updated docs: "Basic Concepts" and "Interface Introduction" chapters updated docs: "Design Overview" chapter added and "Concepts" chapter reworked ``` -------------------------------- ### Run MkDocs Build and Serve Commands Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/new-systems-documentation-generator.md Use these commands to generate and build documentation, or to preview it with live auto-regeneration. ```bash mkdocs build # Generates and builds all documentation mkdocs serve # Live preview with auto-regeneration ``` -------------------------------- ### Example Application: Monitoring a Rectangular Tank Source: https://github.com/mpusz/mp-units/blob/master/docs/examples/storage_tank.md Demonstrates monitoring a rectangular tank being filled with water. This section shows how to instantiate the tank, simulate filling, and output key metrics. ```cpp RectangularTank tank(1.0 * isq::m, 1.0 * isq::m, 1000.0 * isq::kg / isq::m3); auto filled_volume = 0.02 * isq::m3; std::cout << "fill height at 200 s = " << tank.fill_level(filled_volume) << " (20 % full)" << std::endl; std::cout << "fill weight at 200 s = " << tank.filled_weight(filled_volume) << std::endl; std::cout << "spare capacity at 200 s = " << tank.spare_capacity(filled_volume) << std::endl; auto input_flow_rate = 0.1 * isq::kg / isq::s; auto rise_rate = input_flow_rate / (tank.density() * tank.width()); std::cout << "input flow rate = " << input_flow_rate << std::endl; std::cout << "float rise rate = " << rise_rate << std::endl; auto tank_full_eta = tank.capacity() / (input_flow_rate / tank.density()); std::cout << "tank full E.T.A. at current flow rate = " << tank_full_eta << std::endl; ``` -------------------------------- ### Registering Frame Projections for Altitude and Depth Source: https://github.com/mpusz/mp-units/blob/master/docs/tutorials/affine_space/frame_projections.md Register `frame_projection` specializations for converting between `sea_level` (altitude) and `ocean_surface` (depth) origins. Both conversion directions must be explicitly defined. This example demonstrates negating altitude to get depth and vice-versa. ```cpp #include #include #include using namespace mp_units; inline constexpr struct sea_level : absolute_point_origin {} sea_level; inline constexpr struct ocean_surface : absolute_point_origin {} ocean_surface; // Altitude → depth: negate (down is positive in the depth frame) template<> inline constexpr auto mp_units::frame_projection = [](QuantityPointOf auto qp) { return ocean_surface - qp.quantity_from(sea_level); }; // Depth → altitude: inverse (must be defined explicitly — never derived automatically) template<> inline constexpr auto mp_units::frame_projection = [](QuantityPointOf auto qp) { return sea_level - qp.quantity_from(ocean_surface); }; int main() { using namespace mp_units::si::unit_symbols; quantity_point altitude = sea_level + (-100. * m); // 100 m below sea level quantity_point depth = altitude.point_for(ocean_surface); // → depth 100 m (positive downward) quantity_point alt2 = depth.point_for(sea_level); // → altitude −100 m std::cout << "altitude from sea_level: " << altitude.quantity_from(sea_level) << "\n"; std::cout << "depth from ocean_surface: " << depth.quantity_from(ocean_surface) << "\n"; std::cout << "back to sea_level: " << alt2.quantity_from(sea_level) << "\n"; } ``` -------------------------------- ### Add INSTALL option to CMake Source: https://github.com/mpusz/mp-units/blob/master/docs/release_notes.md This CMake option controls whether the project is installed. It is useful for system-wide installations. ```cmake option(INSTALL "Build the install target" ON) ``` -------------------------------- ### Fix latitude and longitude example Source: https://github.com/mpusz/mp-units/blob/master/docs/release_notes.md Corrects the `latitude` and `longitude` example to include `0` for `N` and `E` respectively. This ensures the example accurately represents zero values for these directions. ```cpp `latitude` and `longitude` fixed to include `0` for `N` and `E` respectively ``` -------------------------------- ### Explicit Quantity Point Initialization Examples Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.3.0-released.md Provides multiple syntaxes for explicitly creating a `quantity_point` for temperature, ensuring users understand the correct abstraction for absolute temperature values. ```cpp quantity_point Temperature = absolute(28.0); ``` ```cpp auto Temperature = absolute(28.0); ``` ```cpp quantity_point Temperature(delta(28.0)); ``` -------------------------------- ### Add unit symbols to currency example Source: https://github.com/mpusz/mp-units/blob/master/docs/release_notes.md Updates the currency example to include unit symbols. This makes the example more illustrative and demonstrates how unit symbols can be used in practical scenarios. ```cpp unit symbols added to the currency example ``` -------------------------------- ### Conan Install Command with Update Flag Source: https://github.com/mpusz/mp-units/blob/master/docs/getting_started/installation_and_usage.md This shell command installs Conan dependencies, forcing an update check for the latest recipes. It specifies the C++ standard and enables missing build installs. ```shell conan install . -pr -s compiler.cppstd=20 -b=missing -u ``` -------------------------------- ### Install or Upgrade Conan Source: https://github.com/mpusz/mp-units/blob/master/docs/getting_started/installation_and_usage.md Use this command to install or upgrade the Conan package manager to the latest version. ```shell pip install -U conan ``` -------------------------------- ### Setup Header Files Source: https://github.com/mpusz/mp-units/blob/master/docs/reference/cheat_sheet.md Include the necessary mp-units core and SI system header files. The SI unit symbols namespace must be explicitly included to access short unit symbols like 'm' or 'kg'. ```cpp #include #include using namespace mp_units; using namespace mp_units::si::unit_symbols; // (1)! ``` -------------------------------- ### Add Project Subdirectories Source: https://github.com/mpusz/mp-units/blob/master/CMakeLists.txt Adds the 'src', 'example', and 'test' subdirectories to the build. The 'example' subdirectory is only added if MP_UNITS_API_FREESTANDING is not defined. ```cmake add_subdirectory(src) if(NOT MP_UNITS_API_FREESTANDING) # add usage example add_subdirectory(example) endif() # add unit tests enable_testing() add_subdirectory(test) ``` -------------------------------- ### Get Thermodynamic Temperature with quantity_from_zero() in Kelvin Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/introducing-absolute-quantities.md Use `quantity_from_zero()` on a point already in Kelvin to get its thermodynamic temperature. This is the only case where this function is thermodynamically meaningful. ```cpp point(294.15).quantity_from_zero(); // 294.15 K ✓ ``` -------------------------------- ### Complete Example with Wide Compatibility Source: https://github.com/mpusz/mp-units/blob/master/docs/how_to_guides/integration/wide_compatibility.md Demonstrates the use of mp-units with compatibility features for broad C++ support, including custom quantity specifications, contract macros, and portable formatting. ```cpp #include #include #include #ifdef MP_UNITS_MODULES #include import mp_units; #else #include #include #endif using namespace mp_units; using namespace mp_units::si::unit_symbols; // Define custom quantity specification with wide compatibility QUANTITY_SPEC(flight_distance, isq::length); quantity calculate_distance(quantity speed, quantity duration) { MP_UNITS_EXPECTS(speed > 0 * km / h); MP_UNITS_EXPECTS(duration > 0 * h); return flight_distance(speed * duration); } int main() { quantity speed = 850 * km / h; quantity duration = 2.5 * h; quantity distance = calculate_distance(speed, duration); // Format output with portable macro std::cout << MP_UNITS_STD_FMT::format("Flying at {} for {} covers \n", speed, duration, distance); } ``` -------------------------------- ### Build and Test with All Supported Compilers Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Execute this script to build and test the project across all supported compiler configurations. This is useful for ensuring broad compatibility. ```bash # Build and test with all supported compilers .devcontainer/check_all.sh create ``` -------------------------------- ### Working with Time Points and Durations Source: https://github.com/mpusz/mp-units/blob/master/docs/tutorials/affine_space/points_and_quantities.md Demonstrates creating time points and calculating durations using `quantity_point` and `quantity`. Shows valid operations like subtracting points and adding quantities to points, and highlights invalid operations like adding two points. ```cpp #include #include using namespace mp_units; int main() { using namespace mp_units::si::unit_symbols; // Create time points (absolute positions in time) using implicit origin quantity_point meeting_start{14 * h}; quantity_point meeting_end{16 * h}; // Calculate duration (difference between points) quantity meeting_duration = meeting_end - meeting_start; std::cout << "Meeting duration: " << meeting_duration << "\n"; // Calculate next week's meeting (same time, 7 days later) quantity_point next_meeting = meeting_start + 7 * non_si::day; std::cout << "Next week's meeting: " << next_meeting << " from origin\n"; // These would NOT compile (uncomment to see): // auto wrong = meeting_start + meeting_end; // epresentation{❌} Can't add two points! // But this works: quantity time_until_next = next_meeting - meeting_end; std::cout << "Time until next meeting: " << time_until_next << "\n"; } ``` -------------------------------- ### Correct Quantity Point Initialization Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.3.0-released.md This snippet shows the correct way to initialize a `quantity_point` for temperature, ensuring accurate calculations. This is the recommended approach for temperature values. ```cpp quantity_point Temperature(28.0 * deg_C); ``` -------------------------------- ### Main Function with Typed Quantities Example Source: https://github.com/mpusz/mp-units/blob/master/docs/users_guide/framework_basics/simple_and_typed_quantities.md Demonstrates creating a 'RectangularStorageTank' using typed quantities for dimensions, specifying units like 'mm' for millimeters. This highlights the compile-time safety provided by typed quantities. ```cpp 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)); // ... } ``` -------------------------------- ### Creating a Prefixed Unit Instance Source: https://github.com/mpusz/mp-units/blob/master/docs/users_guide/framework_basics/systems_of_units.md Shows how to create an instance of a prefixed unit (e.g., 'qm' for quecto-metre) by applying the defined prefix to a base unit like 'metre'. ```cpp inline constexpr auto qm = quecto; ``` -------------------------------- ### Work with Units and Create Aliases Source: https://github.com/mpusz/mp-units/blob/master/docs/reference/cheat_sheet.md Demonstrates how to import specific unit symbols, create user-defined aliases for SI units, define derived units (like area and volume), and represent constants as units. Requires importing unit symbols and defining constants. ```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> * π; ``` -------------------------------- ### Main Function for CGS Units Example Source: https://github.com/mpusz/mp-units/blob/master/docs/examples/avg_speed.md This C++ code provides the main function to execute the average speed calculation example using CGS units. It sets up the scenario for both integer and double representations. ```cpp --8<-- "example/avg_speed.cpp:166:" ``` -------------------------------- ### Conan Install and Build Commands Source: https://github.com/mpusz/mp-units/blob/master/docs/getting_started/installation_and_usage.md These shell commands are used to install Conan dependencies, configure CMake using Conan presets, and build the project. The `--build=missing` flag ensures that missing dependencies are built. ```shell conan install . -pr -s compiler.cppstd=20 -b=missing cmake --preset conan-default cmake --build --preset conan-release cmake --build --preset conan-release --target test ``` -------------------------------- ### Alternative Construction Syntax for Points and Quantities Source: https://github.com/mpusz/mp-units/blob/master/docs/tutorials/affine_space/points_and_quantities.md Illustrates two syntaxes for creating quantity points and quantities: direct construction and helper functions. Both methods utilize the library's implicit origin for points. ```cpp quantity duration = 2 * h; // Duration of 2 hours quantity_point meeting{14 * h}; // Point at 14:00 ``` ```cpp quantity duration = delta(2); // Duration of 2 hours quantity_point meeting = point(14); // Point at 14:00 ``` -------------------------------- ### Runtime Arithmetic Overflow Example Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/preventing-integer-overflow.md This example illustrates a runtime arithmetic overflow that cannot be detected at compile time because the values involved in the operation are only known during execution. No general-purpose units library can prevent all such runtime overflows at compile time. ```cpp quantity dist = 100 * m; // 10'000 quantity dist2 = dist + dist; // 20'000 quantity dist4 = dist2 + dist2; // ", ", "⚠️ 40'000 ``` -------------------------------- ### Generate API Reference Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Run this command to generate the API reference documentation for the project. This is typically done as part of the documentation build process. ```bash # Generating API Reference .devcontainer/api_reference.sh ``` -------------------------------- ### Example: Add Celsius to Fahrenheit Conversion Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md This markdown example illustrates how to structure a 'good first issue' for adding a new feature. It specifies the deliverables, rationale, mentorship, skills learned, estimated time, and acceptance criteria. ```markdown ## Good First Issue: Add Celsius to Fahrenheit example **What:** Create a new example in `example/temperature_conversion.cpp` that demonstrates: - Converting between Celsius and Fahrenheit using affine space - Using `quantity_point` for absolute temperatures - Using `quantity` for temperature differences **Why:** Temperature conversion is a common use case that confuses new users. This example will clarify the distinction between absolute and relative temperatures. **Mentorship:** @mpusz will help you through the PR process **Skills Learned:** - C++20 concepts and constraints - mp-units API design patterns - Affine space modeling - Writing clear example code **Estimated Time:** 2 hours ``` -------------------------------- ### Basic Operations with Header Files Source: https://github.com/mpusz/mp-units/blob/master/docs/getting_started/look_and_feel.md Demonstrates simple numeric operations, conversions to common units, and derived quantities using header files. Include the necessary mp-units system headers. ```cpp #include using namespace mp_units; using namespace mp_units::si::unit_symbols; // simple numeric operations static_assert(10 * km / 2 == 5 * km); // conversions to common units 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); static_assert(1000 / (1 * s) == 1 * kHz); ``` -------------------------------- ### Compile-Time Dimensional Safety Check Source: https://github.com/mpusz/mp-units/blob/master/docs/examples/capacitor_time_curve.md Illustrates compile-time checks for dimensional correctness. The first example shows a correct dimensionless argument for `exp()`, while the commented-out second example would fail compilation because `exp()` requires a dimensionless quantity. ```cpp // ✓ Correct: time/time is dimensionless QuantityOf auto dimensionless_arg = -tt / (RR * CC); // ✗ Won't compile: can't take exp of a dimensional quantity // auto wrong = exp(-tt); // Error: exp requires dimensionless! ``` -------------------------------- ### C++ Integer Overflow Example with Unit Conversion Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/preventing-integer-overflow.md Demonstrates how automatic scaling during unit conversion can lead to integer overflow with `int16_t`, even when input and output values fit. This example uses meters and feet, highlighting the intermediate multiplication overflow. ```cpp quantity meters = std::int16_t{20'000} * m; quantity feet = std::int16_t{10'000} * ft; // 1 ft = 381/1250 m quantity total = meters + feet; std::cout << "Result: " << total.force_in(m) << '\n'; // Common unit is m/1250 (or equivalently ft/381) — GCD of the unit representations // Scaling to common unit: // 20'000 m → 20'000 × 1'250 = 25'000'000 (overflows int16_t!) // 10'000 ft → 10'000 × 381 = 3'810'000 (overflows int16_t!) // Sum in common unit: 28'810'000 (overflows int16_t!) // Output: Result: 23048 m (fits int16_t!) ``` -------------------------------- ### Build Documentation with CMake Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Builds the API documentation using CMake after the configuration step. ```bash cmake --build build/docs/api_reference ``` -------------------------------- ### Build and Test with Conan Source: https://github.com/mpusz/mp-units/blob/master/docs/getting_started/contributing.md Use this command to build and test the project with all supported compilers using Conan. Ensure you have the devcontainer environment set up. ```bash # Test with a single compiler configuration conan build . -pr gcc15 -c user.mp-units.build:all=True -b missing ``` ```bash # Build and test with all supported compilers .devcontainer/check_all.sh create ``` -------------------------------- ### Using ISQ Quantity Hierarchies for Type Safety Source: https://github.com/mpusz/mp-units/blob/master/docs/users_guide/systems/isq.md This example demonstrates how to use the defined ISQ quantity hierarchies to ensure type safety at compile time. It shows valid assignments and a commented-out example that would result in a compile-time error due to incompatible hierarchy levels. ```cpp using namespace mp_units::si::unit_symbols; quantity tower_height = 42 * m; quantity walking_distance = 500 * m; // quantity w = tower_height; // Compile-time error! quantity some_length = tower_height; // OK: height is-a length ``` -------------------------------- ### C++ Example of New MP-Units Library Features Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/2.0.0-released.md This C++ code demonstrates the new quantity representation and formatting capabilities of the mp-units library. It requires including the format, isq, and si headers. The example defines a function to calculate average speed and then uses it with different units. ```cpp #include #include #include #include using namespace mp_units; using namespace mp_units::si::unit_symbols; quantity avg_speed(quantity d, quantity t) { return d / t; } int main() { auto speed = avg_speed(220 * km, 2 * h); std::println("{}", speed); // 30.5556 m/s } ``` -------------------------------- ### Practical UAV Operations Example Source: https://github.com/mpusz/mp-units/blob/master/docs/examples/unmanned_aerial_vehicle.md Illustrates realistic UAV scenarios with type-safe, self-documenting, and correctly formatted altitude data. Demonstrates efficient storage with zero runtime overhead for type safety. ```cpp #include "units/quantity.h" #include "units/reference.h" #include "units/systems/angle/degrees.h" #include "units/systems/length/meters.h" #include "units/systems/time/seconds.h" using namespace units; using namespace units::angle; using namespace units::length; using namespace units::time; // ... // Practical UAV operations auto altitude_msl = 1219.20 * meters; auto latitude = 54.24772 * degrees; auto longitude = 18.6745 * degrees; auto altitude_hae = convert>(altitude_msl, latitude, longitude); auto point1 = GeographicPosition(latitude, longitude, altitude_msl); auto point2 = GeographicPosition(latitude, longitude, 1219.20 * meters + 2925.00 * meters); auto relative_altitude = quantity_from(point2) - quantity_from(point1); std::cout << "HAL: " << altitude_hal.in(meters) << "\n"; std::cout << "AGL: " << altitude_agl.in(meters) << "\n"; std::cout << "EPPR: " << latitude << " " << longitude << ", " << altitude_msl.in(meters) << " AMSL, " << altitude_hae.in(meters) << " HAE(EGM2008-1)\n"; std::cout << "Relative Altitude: " << relative_altitude.in(meters) << "\n"; ``` -------------------------------- ### Integer Division Example Source: https://github.com/mpusz/mp-units/blob/master/docs/blog/posts/preventing-integer-overflow.md This C++ code demonstrates a common pitfall with integer division where the order of operations and unit conversion can lead to incorrect results. The example calculates the number of 40-minute intervals in 8 hours, but due to integer division (8 / 40 = 0), the result is wrong. ```cpp // Apparent time ratio — how many 40-minute intervals in 8 hours? hours(8) / minutes(40) // Expected: 12. Actual with integer division: // 8 / 40 = 0, then unit factor applied → wrong! ``` -------------------------------- ### Build and Test with Single Compiler Configuration Source: https://github.com/mpusz/mp-units/blob/master/CONTRIBUTING.md Use this command to build and test the project with a specific compiler configuration, such as GCC 15. The `-c user.mp-units.build:all=True` flag enables all user-defined builds, and `-b missing` ensures missing dependencies are built. ```bash # Test with a single compiler configuration conan build . -pr gcc15 -c user.mp-units.build:all=True -b missing ```