Skip to content

Commit

Permalink
Add function as() to cast conveniently between units of the same type
Browse files Browse the repository at this point in the history
  • Loading branch information
bernedom committed Feb 14, 2022
1 parent b59d8e1 commit 350b0c4
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<unit_t>()` to unit for convenient conversion to a unit of the same type but different ratio

## 2.4.0

Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<gramt_t>();

void calculate_mass(const SI::kilo_gram_t<long double> &kg) {
// do something meaningful here
}

int main(int, char **) {
calculate_mass(one_kilogramm);
calculate_mass(one_kilogram);
return 0;
}
```
Expand All @@ -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<double, std::ratio<1000, 36>>` would be "kilometre per one-hundreth-of-an-hour".
Converting between units is either done with the `as<unit_t>()` member function of `unit_` or the free function `SI::unit_cast<unit_t>(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)
Expand Down
10 changes: 10 additions & 0 deletions include/SI/detail/unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ struct unit_t {
/// returns the stored value as raw type
constexpr _type value() const { return value_; }

template <typename _unit_rhs> 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<typename _unit_rhs::exponent, _exponent>,
"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; }

Expand Down
12 changes: 12 additions & 0 deletions test/src/detail_tests/unit_t_conversions_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<unit<std::milli>() THHEN value is multiplied by 1000000 ") {
constexpr unit_t<'X', std::ratio<1>, int64_t, std::kilo> v{2};
constexpr auto result =
v.as<unit_t<'X', std::ratio<1>, int64_t, std::milli>>();

STATIC_REQUIRE(
std::is_same<const unit_t<'X', std::ratio<1>, int64_t, std::milli>,
decltype(result)>::value);
STATIC_REQUIRE(result.value() == 2000000);
}

0 comments on commit 350b0c4

Please sign in to comment.