From 350b0c4521da15fc6b6f7205489438d935fe9c34 Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Sun, 13 Feb 2022 22:14:11 +0100 Subject: [PATCH] Add function as() to cast conveniently between units of the same type --- CHANGELOG.md | 1 + README.md | 7 +++++-- include/SI/detail/unit.h | 10 ++++++++++ test/src/detail_tests/unit_t_conversions_tests.cc | 12 ++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75568b75..69d353d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.4.1 * Fix reported [issue](https://github.com/bernedom/SI/issues/101) that `operator/(scalar / unit)` would calculate the ratio into the value. +* Add function `as()` to unit for convenient conversion to a unit of the same type but different ratio ## 2.4.0 diff --git a/README.md b/README.md index 230d14a6..1866e395 100644 --- a/README.md +++ b/README.md @@ -22,16 +22,17 @@ An illustrative example: using namespace SI::literals; -constexpr auto one_kilogramm = 1.0_kg; +constexpr auto one_kilogram = 1.0_kg; constexpr auto ten_coulomb = 5.0_A * 2.0_s; constexpr auto half_an_ampere = ten_coulomb / 20.0_s; +constexpr auto tousand_gramms = one_kilogram.as(); void calculate_mass(const SI::kilo_gram_t &kg) { // do something meaningful here } int main(int, char **) { - calculate_mass(one_kilogramm); + calculate_mass(one_kilogram); return 0; } ``` @@ -40,6 +41,8 @@ SI provides conversions and arithmetic operations with values of any of the [Int It is possible to supply custom ratios to the built-in types and they are fully compatible for calculation with other units. However, the necessary literals or typedefs have to be supplied by the user. For instance `SI::velocity_t>` would be "kilometre per one-hundreth-of-an-hour". +Converting between units is either done with the `as()` member function of `unit_` or the free function `SI::unit_cast(unit_t u)`. This will convert a value of the same type but different ratio. + ## SI Base units For each unit the available literals are the implemented ratios prefixed with an underscore. i.e. `_mm`. `_km`. Generally the ratios follow [metric prefixes of the international system of units](https://en.wikipedia.org/wiki/Metric_prefix) diff --git a/include/SI/detail/unit.h b/include/SI/detail/unit.h index 290bde9a..def770f0 100644 --- a/include/SI/detail/unit.h +++ b/include/SI/detail/unit.h @@ -99,6 +99,16 @@ struct unit_t { /// returns the stored value as raw type constexpr _type value() const { return value_; } + template constexpr _unit_rhs as() const { + static_assert(is_unit_t_v<_unit_rhs>, "only supported for SI::unit_t"); + static_assert(std::ratio_equal_v, + "Exponents must match"); + static_assert(_unit_rhs::symbol::value == _symbol, + "target unit must be of the same type must match"); + + return unit_cast<_unit_rhs>(*this); + } + ///@todo set as friend to the stream-function void setValue(_type v) { value_ = v; } diff --git a/test/src/detail_tests/unit_t_conversions_tests.cc b/test/src/detail_tests/unit_t_conversions_tests.cc index 2edc6bed..139ff80f 100644 --- a/test/src/detail_tests/unit_t_conversions_tests.cc +++ b/test/src/detail_tests/unit_t_conversions_tests.cc @@ -339,3 +339,15 @@ TEST_CASE("GIVEN a unit with internal type of int32_t WHEN static_cast to unit " decltype(result)>::value); STATIC_REQUIRE(result.value() == 2000); } + +TEST_CASE("GIVEN a unit with internal ratio of kilo WHEN retrieved with " + "as() THHEN value is multiplied by 1000000 ") { + constexpr unit_t<'X', std::ratio<1>, int64_t, std::kilo> v{2}; + constexpr auto result = + v.as, int64_t, std::milli>>(); + + STATIC_REQUIRE( + std::is_same, int64_t, std::milli>, + decltype(result)>::value); + STATIC_REQUIRE(result.value() == 2000000); +} \ No newline at end of file