diff --git a/src/include/units/bits/tools.h b/src/include/units/bits/tools.h index c4b4edda..00094b5d 100644 --- a/src/include/units/bits/tools.h +++ b/src/include/units/bits/tools.h @@ -100,15 +100,15 @@ namespace units { // common_ratio // todo: simplified - template + template struct common_ratio { - using gcd_num = static_gcd; - using gcd_den = static_gcd; - using type = std::ratio; + using gcd_num = static_gcd; + using gcd_den = static_gcd; + using type = std::ratio; }; - template - using common_ratio_t = typename common_ratio::type; + template + using common_ratio_t = typename common_ratio::type; // upcasting diff --git a/src/include/units/frequency.h b/src/include/units/frequency.h index c2e8b37e..aa6efce0 100644 --- a/src/include/units/frequency.h +++ b/src/include/units/frequency.h @@ -39,7 +39,7 @@ namespace units { struct millihertz : unit {}; template<> struct upcasting_traits> : upcast_to {}; - struct hertz : unit> {}; + struct hertz : derived_unit {}; template<> struct upcasting_traits> : upcast_to {}; struct kilohertz : unit {}; diff --git a/src/include/units/unit.h b/src/include/units/unit.h index 067a1364..fed8ff3b 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -50,4 +50,66 @@ namespace units { std::is_empty_v && detail::is_unit>; + + // derived_unit + + namespace detail { + + template + struct get_unit_base_dim; + + template + struct get_unit_base_dim> { + static_assert(sizeof...(Rest) == 0, "Base unit expected"); + using dimension = typename E::dimension; + }; + + template + struct get_ratio { + using ratio = std::ratio<1>; + }; + + template + struct get_ratio { + using unit_base_dim = typename get_unit_base_dim::dimension; + using ratio = std::conditional_t::ratio>; + }; + + template + struct ratio_op; + + template + struct ratio_op { + using ratio = Result; + }; + + template + struct ratio_op { + using calc_ratio = std::conditional_t<(UnitExpValue > 0), std::ratio_multiply, + std::ratio_divide>; + static constexpr int value = UnitExpValue > 0 ? UnitExpValue - 1 : UnitExpValue + 1; + using ratio = typename ratio_op::ratio; + }; + + template + struct derived_ratio; + + template + struct derived_ratio, Us...> { + using ratio = std::ratio<1>; + }; + + template + struct derived_ratio, Us...> { + using rest_ratio = typename derived_ratio, Us...>::ratio; + using e_ratio = typename get_ratio::ratio; + using ratio = typename ratio_op::ratio; + }; + + } + + template + using derived_unit = unit::ratio>; + } // namespace units diff --git a/src/include/units/velocity.h b/src/include/units/velocity.h index 9cec999e..3d6e8bec 100644 --- a/src/include/units/velocity.h +++ b/src/include/units/velocity.h @@ -22,7 +22,6 @@ #pragma once -#include #include #include @@ -37,13 +36,13 @@ namespace units { template using velocity = quantity; - struct meter_per_second : unit> {}; + struct meter_per_second : derived_unit {}; template<> struct upcasting_traits> : upcast_to {}; - struct kilometer_per_hour : unit> {}; + struct kilometer_per_hour : derived_unit {}; template<> struct upcasting_traits> : upcast_to {}; - struct mile_per_hour : unit> {}; + struct mile_per_hour : derived_unit {}; template<> struct upcasting_traits> : upcast_to {}; inline namespace literals { diff --git a/test/test_units.cpp b/test/test_units.cpp index aa8cf785..17ffbb48 100644 --- a/test/test_units.cpp +++ b/test/test_units.cpp @@ -38,12 +38,7 @@ namespace { using namespace units; - // frequency - - static_assert(2 / 1_s == 2_Hz); - static_assert(1000 / 1_s == 1_kHz); - static_assert(1 / 1_ms == 1_kHz); - static_assert(3.2_GHz == 3'200'000'000_Hz); + /* ************** BASE DIMENSIONS **************** */ // time @@ -65,6 +60,17 @@ namespace { // static_assert(5_in + 8_cm == 207_mm); + + + /* ************** DERIVED DIMENSIONS **************** */ + + // frequency + + static_assert(2 / 1_s == 2_Hz); + static_assert(1000 / 1_s == 1_kHz); + static_assert(1 / 1_ms == 1_kHz); + static_assert(3.2_GHz == 3'200'000'000_Hz); + // velocity static_assert(std::is_same_v>, long long int>>);