diff --git a/src/include/units/bits/tools.h b/src/include/units/bits/tools.h index 6660c1eb..f8625825 100644 --- a/src/include/units/bits/tools.h +++ b/src/include/units/bits/tools.h @@ -30,6 +30,22 @@ namespace units { using namespace mp::std_concepts; // todo Remove when std::concepts will arrive + template + concept bool Number = requires(T a, T b) { + { a + b} -> T; + { a - b } -> T; + { a * b } -> T; + { a / b } -> T; + { -a } -> T; + { a += b } -> T&; + { a -= b } -> T&; + { a *= b } -> T&; + { a /= b } -> T&; + { T{0} };// can construct a T from a zero + // … + } ; + + // static_sign template diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 9fb4dff7..296879a4 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -29,8 +29,9 @@ namespace units { // is_quantity - template - requires Same class quantity; + template + requires Same + class quantity; namespace detail { @@ -38,7 +39,7 @@ namespace units { struct is_quantity : std::false_type { }; - template + template struct is_quantity> : std::true_type { }; @@ -60,38 +61,38 @@ namespace units { namespace detail { - template + template struct quantity_cast_impl { - template - static constexpr To cast(const quantity, Rep>& q) + template + static constexpr To cast(const Q& q) { return To(static_cast(static_cast(q.count()) * static_cast(CR::num) / static_cast(CR::den))); } }; - template + template struct quantity_cast_impl { - template - static constexpr To cast(const quantity, Rep>& q) + template + static constexpr To cast(const Q& q) { return To(static_cast(q.count())); } }; - template + template struct quantity_cast_impl { - template - static constexpr To cast(const quantity, Rep>& q) + template + static constexpr To cast(const Q& q) { return To(static_cast(static_cast(q.count()) / static_cast(CR::den))); } }; - template + template struct quantity_cast_impl { - template - static constexpr To cast(const quantity, Rep>& q) + template + static constexpr To cast(const Q& q) { return To(static_cast(static_cast(q.count()) * static_cast(CR::num))); } @@ -99,8 +100,9 @@ namespace units { } // namespace detail - template - requires Same constexpr To quantity_cast(const quantity& q) + template + requires Same constexpr + To quantity_cast(const quantity& q) { using c_ratio = std::ratio_divide; using c_rep = std::common_type_t; @@ -110,7 +112,7 @@ namespace units { // quantity_values - template + template struct quantity_values { static constexpr Rep zero() { return Rep(0); } static constexpr Rep max() { return std::numeric_limits::max(); } @@ -119,8 +121,9 @@ namespace units { // quantity - template - requires Same class quantity { + template + requires Same + class quantity { Rep value_; public: @@ -135,8 +138,8 @@ namespace units { template requires ConvertibleTo && - (treat_as_floating_point_v || !treat_as_floating_point_v)constexpr explicit quantity(const Rep2& r) - : value_{static_cast(r)} + (treat_as_floating_point_v || !treat_as_floating_point_v) + constexpr explicit quantity(const Rep2& r) : value_{static_cast(r)} { } @@ -144,8 +147,8 @@ namespace units { requires Same&& ConvertibleTo && (treat_as_floating_point_v || (std::ratio_divide::den == 1 && - !treat_as_floating_point_v)) constexpr quantity(const Q2& q) - : value_{quantity_cast(q).count()} + !treat_as_floating_point_v)) + constexpr quantity(const Q2& q) : value_{quantity_cast(q).count()} { } @@ -212,7 +215,7 @@ namespace units { }; // clang-format off - template + template std::common_type_t, quantity> constexpr operator+(const quantity& lhs, const quantity& rhs) @@ -221,7 +224,7 @@ namespace units { return ret(ret(lhs).count() + ret(rhs).count()); } - template + template std::common_type_t, quantity> constexpr operator-(const quantity& lhs, const quantity& rhs) @@ -230,7 +233,7 @@ namespace units { return ret(ret(lhs).count() - ret(rhs).count()); } - template + template quantity> constexpr operator*(const quantity& q, const Rep2& v) @@ -239,7 +242,7 @@ namespace units { return ret(ret(q).count() * v); } - template + template quantity> constexpr operator*(const Rep1& v, const quantity& q) @@ -247,7 +250,7 @@ namespace units { return q * v; } - template + template requires treat_as_floating_point_v> || std::ratio_multiply::den == 1 quantity, unit, std::ratio_multiply>, std::common_type_t> constexpr operator*(const quantity& lhs, @@ -258,7 +261,7 @@ namespace units { return ret(lhs.count() * rhs.count()); } - template + template quantity...>, unit...>, std::ratio>, std::common_type_t> constexpr operator/(const Rep1& v, const quantity, U, Rep2>& q) @@ -269,7 +272,7 @@ namespace units { return ret(v / den(q).count()); } - template + template quantity> constexpr operator/(const quantity& q, const Rep2& v) @@ -278,7 +281,7 @@ namespace units { return ret(ret(q).count() / v); } - template + template std::common_type_t constexpr operator/(const quantity& lhs, const quantity& rhs) @@ -287,7 +290,7 @@ namespace units { return cq(lhs).count() / cq(rhs).count(); } - template + template requires treat_as_floating_point_v> || std::ratio_divide::den == 1 quantity, unit, std::ratio_divide>, std::common_type_t> constexpr operator/(const quantity& lhs, @@ -298,7 +301,7 @@ namespace units { return ret(lhs.count() / rhs.count()); } - template + template quantity> constexpr operator%(const quantity& q, const Rep2& v) @@ -307,7 +310,7 @@ namespace units { return ret(ret(q).count() % v); } - template + template std::common_type_t, quantity> constexpr operator%(const quantity& lhs, const quantity& rhs) @@ -318,39 +321,39 @@ namespace units { // clang-format on - template + template constexpr bool operator==(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t, quantity>; return ct(lhs).count() == ct(rhs).count(); } - template + template constexpr bool operator!=(const quantity& lhs, const quantity& rhs) { return !(lhs == rhs); } - template + template constexpr bool operator<(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t, quantity>; return ct(lhs).count() < ct(rhs).count(); } - template + template constexpr bool operator<=(const quantity& lhs, const quantity& rhs) { return !(rhs < lhs); } - template + template constexpr bool operator>(const quantity& lhs, const quantity& rhs) { return rhs < lhs; } - template + template constexpr bool operator>=(const quantity& lhs, const quantity& rhs) { return !(lhs < rhs); @@ -360,8 +363,13 @@ namespace units { namespace std { + template + struct common_type, units::quantity> { + using type = units::quantity>; + }; + // todo: simplified - template + template struct common_type, units::quantity> { using type = units::quantity>, std::common_type_t>; diff --git a/test/test_quantity.cpp b/test/test_quantity.cpp index 73e329c6..d8ba1cf7 100644 --- a/test/test_quantity.cpp +++ b/test/test_quantity.cpp @@ -23,6 +23,7 @@ #include "units/si/velocity.h" #include #include + using namespace units; using namespace units::literals; @@ -30,12 +31,17 @@ namespace { template class my_value { - T data_{}; + T value_{}; public: my_value() = default; - constexpr my_value(T v) : data_{v} {} - constexpr operator T() const { return data_; } + constexpr my_value(T v) : value_{v} {} + constexpr my_value& operator+=(const my_value& other) { value_ += other.value_; return *this; } + constexpr my_value& operator-=(const my_value& other) { value_ -= other.value_; return *this; } + constexpr my_value& operator*=(const my_value& other) { value_ *= other.value_; return *this; } + constexpr my_value& operator/=(const my_value& other) { value_ /= other.value_; return *this; } + constexpr operator const T&() const { return value_; } + constexpr operator T&() { return value_; } }; } // namespace @@ -74,15 +80,15 @@ namespace { // class invariants - // constexpr quantity q; // should a static_assert - // constexpr quantity> error(0_m); // should trigger a static_assert - // constexpr quantity error(0); // should trigger a static_assert - // constexpr quantity> error(0); // should trigger a static_assert + // constexpr quantity q; // should a static_assert + // constexpr quantity> error(0_m); // should trigger a static_assert + // constexpr quantity error(0); // should trigger a static_assert + // constexpr quantity>, int> error(0); // should trigger a static_assert // member types static_assert(std::is_same_v::rep, int>); - static_assert(std::is_same_v::rep, float>); + static_assert(std::is_same_v::rep, double>); static_assert(std::is_same_v::unit, meter>); static_assert(std::is_same_v::unit, kilometer>); @@ -94,30 +100,30 @@ namespace { static_assert(length(km).count() == km.count()); static_assert(length(1).count() == 1); - static_assert(length(my_value(1)).count() == 1); + static_assert(length(my_value(1)).count() == 1); static_assert(length>(1).count() == 1); // static_assert(length(1.0).count() == 1); // should not compile - // static_assert(length(my_value(1.0)).count() == 1); // should not compile - // static_assert(length>(1.0).count() == 1); // should not compile - static_assert(length(1.0).count() == 1.0); - static_assert(length(my_value(1.0)).count() == 1.0); - static_assert(length(1).count() == 1.0); - static_assert(length(my_value(1)).count() == 1.0); - static_assert(length(3.14f).count() == 3.14f); - static_assert(length>(1.0).count() == 1.0); - static_assert(length>(1).count() == 1.0); - static_assert(length>(3.14f).count() == 3.14f); + // static_assert(length(my_value(1.0)).count() == 1); // should not compile + // static_assert(length(1.0).count() == 1); // should not compile + static_assert(length(1.0).count() == 1.0); + static_assert(length(my_value(1.0)).count() == 1.0); + static_assert(length(1).count() == 1.0); + static_assert(length(my_value(1)).count() == 1.0); + static_assert(length(3.14).count() == 3.14); + static_assert(length>(1.0).count() == 1.0); + static_assert(length>(1).count() == 1.0); + static_assert(length>(3.14).count() == 3.14); static_assert(length(km).count() == 1000); - // static_assert(length(length(3.14)).count() == 3); // should not compile + // static_assert(length(length(3.14)).count() == 3); // should not compile static_assert(length(quantity_cast>(3.14_m)).count() == 3); - // static_assert(length(length>(1000.0)).count() == 1000); // should not compile - // static_assert(length>(1000.0_m).count() == 1000); // should not compile - static_assert(length(1000.0_m).count() == 1000.0); - static_assert(length(length>(1000.0)).count() == 1000.0); - static_assert(length>(1000.0_m).count() == 1000.0); - static_assert(length(km).count() == 1000.0); - static_assert(length>(km).count() == 1000.0); + // static_assert(length(length>(1000.0)).count() == 1000); // should not compile + // static_assert(length(1000.0_m).count() == 1000); // should not compile + static_assert(length(1000.0_m).count() == 1000.0); + static_assert(length(length>(1000.0)).count() == 1000.0); + static_assert(length>(1000.0_m).count() == 1000.0); + static_assert(length(km).count() == 1000.0); + static_assert(length>(km).count() == 1000.0); static_assert(length(1_km).count() == 1000); // static_assert(length(1_s).count() == 1); // should not compile // static_assert(length(1010_m).count() == 1); // should not compile @@ -136,15 +142,15 @@ namespace { static_assert(length::zero().count() == 0); static_assert(length::min().count() == std::numeric_limits::lowest()); static_assert(length::max().count() == std::numeric_limits::max()); - static_assert(length::zero().count() == 0.0); - static_assert(length::min().count() == std::numeric_limits::lowest()); - static_assert(length::max().count() == std::numeric_limits::max()); + static_assert(length::zero().count() == 0.0); + static_assert(length::min().count() == std::numeric_limits::lowest()); + static_assert(length::max().count() == std::numeric_limits::max()); static_assert(length>::zero().count() == 0); static_assert(length>::min().count() == std::numeric_limits::lowest()); static_assert(length>::max().count() == std::numeric_limits::max()); - static_assert(length>::zero().count() == 0.0); - static_assert(length>::min().count() == std::numeric_limits::lowest()); - static_assert(length>::max().count() == std::numeric_limits::max()); + static_assert(length>::zero().count() == 0.0); + static_assert(length>::min().count() == std::numeric_limits::lowest()); + static_assert(length>::max().count() == std::numeric_limits::max()); // unary member operators @@ -183,14 +189,20 @@ namespace { // non-member arithmetic operators - static_assert(std::is_same_v() + length()), length>); - static_assert(std::is_same_v() - length()), length>); - static_assert(std::is_same_v() * 1.0f), length>); - static_assert(std::is_same_v()), length>); - static_assert(std::is_same_v() / 1.0f), length>); - static_assert(std::is_same_v() / length()), float>); - static_assert(std::is_same_v() % short(1)), length>); - static_assert(std::is_same_v() % length(1)), length>); + static_assert(std::is_same_v() + length()), quantity>); + static_assert(std::is_same_v() + length()), quantity>); + static_assert(std::is_same_v() + length()), quantity>, double>>); + static_assert(std::is_same_v() - length()), quantity>); + static_assert(std::is_same_v() - length()), quantity>, double>>); + static_assert(std::is_same_v() * 1.0), quantity>); + static_assert(std::is_same_v()), quantity>); + static_assert(std::is_same_v() * units::time()), quantity>, int>>); + static_assert(std::is_same_v() / 1.0), quantity>); + static_assert(std::is_same_v() / length()), double>); + static_assert(std::is_same_v() / length()), double>); + static_assert(std::is_same_v() / units::time()), quantity>); + static_assert(std::is_same_v() % short(1)), quantity>); + static_assert(std::is_same_v() % length(1)), quantity>); static_assert((1_m + km).count() == 1001); static_assert((1_m + 1_km).count() == 1001); @@ -242,9 +254,9 @@ namespace { // common_type - static_assert(std::is_same_v, length>, length>); - static_assert(std::is_same_v, length>, length>); - static_assert(std::is_same_v, length>, length>); + static_assert(std::is_same_v, length>, length>, int>>); + static_assert(std::is_same_v, length>, length>, long long>>); + static_assert(std::is_same_v, length>, length>, double>>); // quantity_cast diff --git a/test/test_units.cpp b/test/test_units.cpp index 101561cb..1ec614d7 100644 --- a/test/test_units.cpp +++ b/test/test_units.cpp @@ -48,7 +48,9 @@ namespace { static_assert(10_km / 5_km == 2); static_assert(10_km / 2 == 5_km); - static_assert(1_m == 100_cm)//static_assert(5_in + 8_cm == 207_mm); +// static_assert(1_ft == 12_in); + static_assert(1_m == 100_cm); +// static_assert(5_in + 8_cm == 207_mm); // velocity