From f31b26b5e5e2741cd5b09efbae61afbc7bbd35a8 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 6 Dec 2019 12:18:39 +0100 Subject: [PATCH] Design cleanup - unknown_unit added - examples refactored - base_type renamed to downcast_base_type - scaled_unit renamed to named_scaled_unit - detail::reference_unit renamed to scaled_unit - quantity_test cleanup --- CMakeLists.txt | 2 +- example/CMakeLists.txt | 18 +-- example/avg_velocity.cpp | 147 ++++++++++++++++++ example/measurement.cpp | 43 +++-- .../{example.cpp => unknown_dimension.cpp} | 40 ++--- src/include/units/bits/downcasting.h | 8 +- src/include/units/bits/unit_concept.h | 11 +- src/include/units/derived_dimension.h | 36 ++++- src/include/units/math.h | 4 +- src/include/units/physical/dimensions.h | 2 +- .../si}/acceleration.h | 26 ++-- src/include/units/physical/si/length.h | 8 +- src/include/units/physical/si/time.h | 4 +- src/include/units/quantity.h | 14 +- src/include/units/unit.h | 40 ++--- .../make_dimension/dimension_concepts_all.h | 6 +- .../make_dimension/dimension_concepts_iface.h | 6 +- .../make_dimension/dimension_no_concepts.h | 6 +- .../make_dimension/downcasting_concepts_all.h | 8 +- .../make_dimension/downcasting_no_concepts.h | 4 +- test/unit_test/static/quantity_test.cpp | 65 ++++---- test/unit_test/static/unit_test.cpp | 16 +- 22 files changed, 354 insertions(+), 160 deletions(-) create mode 100644 example/avg_velocity.cpp rename example/{example.cpp => unknown_dimension.cpp} (65%) rename src/include/units/{dimensions => physical/si}/acceleration.h (62%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 931c79d1..863addb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,4 +42,4 @@ add_subdirectory(src) add_subdirectory(test) # add usage example -#add_subdirectory(example) +add_subdirectory(example) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index fb500daf..d9f229c5 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -20,15 +20,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -# example app -add_executable(example example.cpp) -target_link_libraries(example - PRIVATE - mp::units -) +function(add_example target) + add_executable(${target} ${target}.cpp) + target_link_libraries(${target} PRIVATE mp::units) +endfunction() -add_executable(measurement measurement.cpp) -target_link_libraries(measurement - PRIVATE - mp::units -) +add_example(avg_velocity) +add_example(measurement) +add_example(unknown_dimension) diff --git a/example/avg_velocity.cpp b/example/avg_velocity.cpp new file mode 100644 index 00000000..5c34003a --- /dev/null +++ b/example/avg_velocity.cpp @@ -0,0 +1,147 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +namespace { + +constexpr units::si::velocity +fixed_int_si_avg_speed(units::si::length d, + units::si::time t) +{ + return d / t; +} + +constexpr units::si::velocity +fixed_double_si_avg_speed(units::si::length d, + units::si::time t) +{ + return d / t; +} + +template +constexpr units::Velocity AUTO si_avg_speed(units::si::length d, + units::si::time t) +{ + return d / t; +} + +constexpr units::Velocity AUTO avg_speed(units::Length AUTO d, units::Time AUTO t) +{ + return d / t; +} + +template +void print_result(D distance, T duration, V velocity) +{ + const auto result_in_kmph = units::quantity_cast(velocity); + std::cout << "Average speed of a car that makes " << distance << " in " + << duration << " is " << result_in_kmph << ".\n"; +} + +void example() +{ + using namespace units; + using namespace units::si::literals; + + // SI (int) + { + constexpr Length AUTO distance = 220km; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "SI units with 'int' as representation\n"; + + print_result(distance, duration, fixed_int_si_avg_speed(distance, duration)); + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + + // the framework will not allow a division (and multiplication) of different dimensions + // with two integral representation (at least one of them have to ba floating-point one) + print_result(distance, duration, si_avg_speed(quantity_cast(distance), duration)); + print_result(distance, duration, avg_speed(quantity_cast(distance), duration)); + } + + // SI (double) + { + constexpr Length AUTO distance = 220.km; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "\nSI units with 'double' as representation\n"; + + // conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast(distance), quantity_cast(duration))); + + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + print_result(distance, duration, si_avg_speed(distance, duration)); + print_result(distance, duration, avg_speed(distance, duration)); + } + + // Customary Units (int) + { + constexpr Length AUTO distance = 140mi; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "\nUS Customary Units with 'int' as representation\n"; + + // it is not possible to make a lossless conversion of miles to meters on an integral type + // (explicit cast needed) + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast(distance), duration)); + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + + // the framework will not allow a division (and multiplication) of different dimensions + // with two integral representation (at least one of them have to ba floating-point one) + print_result(distance, duration, si_avg_speed(quantity_cast(distance), duration)); + print_result(distance, duration, avg_speed(quantity_cast(distance), duration)); + } + + // Customary Units (double) + { + constexpr Length AUTO distance = 140.mi; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "\nUS Customary Units with 'double' as representation\n"; + + // conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed + // also it is not possible to make a lossless conversion of miles to meters on an integral type + // (explicit cast needed) + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast(distance), quantity_cast(duration))); + + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + print_result(distance, duration, si_avg_speed(distance, duration)); + print_result(distance, duration, avg_speed(distance, duration)); + } +} + +} // namespace + +int main() +{ + try { + example(); + } + catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } + catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/example/measurement.cpp b/example/measurement.cpp index 09c6b6e1..db7163a5 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -20,14 +20,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include +#include #include namespace { - template typename Trait> - concept Satisfies = Trait::value; - // root sum of squares template T rss(const T& v1, const T& v2) @@ -118,24 +115,38 @@ namespace { value_type uncertainty_{}; }; - template - using m_quantity = units::quantity>; - } // namespace template inline constexpr bool units::treat_as_floating_point> = std::is_floating_point_v; +namespace { + +void example() +{ + using namespace units; + + const auto a = si::acceleration>(measurement(9.8, 0.1)); + const auto t = si::time>(measurement(1.2, 0.1)); + + const Velocity AUTO v1 = a * t; + std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast(v1) << '\n'; + + si::length> length(measurement(123., 1.)); + std::cout << "10 * " << length << " = " << 10 * length << '\n'; +} + +} // namespace int main() { - const auto a = m_quantity(measurement(9.8, 0.1)); - const auto t = m_quantity(measurement(1.2, 0.1)); - - units::Velocity AUTO v1 = a * t; - m_quantity v2(v1); - std::cout << a << " * " << t << " = " << v1 << " = " << v2 << '\n'; - - m_quantity length(measurement(123., 1.)); - std::cout << "10 * " << length << " = " << 10 * length << '\n'; + try { + example(); + } + catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } + catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } } diff --git a/example/example.cpp b/example/unknown_dimension.cpp similarity index 65% rename from example/example.cpp rename to example/unknown_dimension.cpp index c1716594..9cd31340 100644 --- a/example/example.cpp +++ b/example/unknown_dimension.cpp @@ -20,43 +20,43 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include +#include #include namespace { -using namespace units::literals; - template constexpr units::Velocity AUTO avg_speed(D d, T t) { return d / t; } -template -void example_1(V v, T t) +void example() { - const units::Length AUTO distance = v * t; - std::cout << "A car driving " << v << " in a time of " << t << " will pass " - << units::quantity_cast>(distance) << ".\n"; + using namespace units::si::literals; + + units::Length AUTO d1 = 123m; + units::Time AUTO t1 = 10s; + units::Velocity AUTO v1 = avg_speed(d1, t1); + + auto temp1 = v1 * 50m; // produces intermediate unknown dimension with 'unknown_unit' as its 'coherent_unit' + units::Velocity AUTO v2 = temp1 / 100m; // back to known dimensions again + units::Length AUTO d2 = v2 * 60s; + + std::cout << "d1 = " << d1 << '\n'; + std::cout << "t1 = " << t1 << '\n'; + std::cout << "v1 = " << v1 << '\n'; + std::cout << "temp1 = " << temp1 << '\n'; + std::cout << "v2 = " << v2 << '\n'; + std::cout << "d2 = " << d2 << '\n'; } -void example_2(double distance_v, double duration_v) -{ - units::quantity distance(distance_v); - units::quantity duration(duration_v); - const auto kmph = quantity_cast(avg_speed(distance, duration)); - std::cout << "Average speed of a car that makes " << distance << " in " - << duration << " is " << kmph << ".\n"; -} - -} +} // namespace int main() { try { - example_1(60kmph, 10.0min); - example_2(220, 2); + example(); } catch (const std::exception& ex) { std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; diff --git a/src/include/units/bits/downcasting.h b/src/include/units/bits/downcasting.h index 043b1522..822bf909 100644 --- a/src/include/units/bits/downcasting.h +++ b/src/include/units/bits/downcasting.h @@ -29,16 +29,16 @@ namespace units { template struct downcast_base { - using base_type = BaseType; + using downcast_base_type = BaseType; friend auto downcast_guide(downcast_base); }; template concept Downcastable = requires { - typename T::base_type; + typename T::downcast_base_type; } && - std::derived_from>; + std::derived_from>; template struct downcast_child : T { @@ -67,6 +67,6 @@ namespace units { using downcast = decltype(detail::downcast_impl()); template - using downcast_base_t = T::base_type; + using downcast_base_t = T::downcast_base_type; } // namespace units diff --git a/src/include/units/bits/unit_concept.h b/src/include/units/bits/unit_concept.h index 1f60253a..d8e675b3 100644 --- a/src/include/units/bits/unit_concept.h +++ b/src/include/units/bits/unit_concept.h @@ -27,15 +27,14 @@ namespace units { -namespace detail { +template +concept UnitRatio = Ratio && (R::num * R::den > 0); -template -struct reference_unit; - -} // namespace detail +template +struct scaled_unit; // Unit template -concept Unit = is_derived_from_instantiation; +concept Unit = is_derived_from_instantiation; } // namespace units diff --git a/src/include/units/derived_dimension.h b/src/include/units/derived_dimension.h index 78f109ec..35e969db 100644 --- a/src/include/units/derived_dimension.h +++ b/src/include/units/derived_dimension.h @@ -246,15 +246,39 @@ struct derived_dimension : downcast_child +concept PredefinedDimension = Dimension && requires { typename T::coherent_unit; }; + +template +auto unit_for_dimension_impl() +{ + if constexpr(PredefinedDimension) { + return downcast>{}; + } + else { + return scaled_unit{}; + } +} + +template +using unit_for_dimension = decltype(unit_for_dimension_impl()); + +} + // same_dim template -inline constexpr bool same_dim; +inline constexpr bool same_dim = false; template inline constexpr bool same_dim = std::is_same_v; template -inline constexpr bool same_dim = std::is_same_v; +inline constexpr bool same_dim = std::is_same_v; // dim_invert namespace detail { @@ -321,7 +345,7 @@ struct dimension_multiply_impl { template struct dimension_multiply_impl { - using type = downcast>, typename D2::base_type>>; + using type = downcast>, typename D2::downcast_base_type>>; }; template @@ -331,7 +355,7 @@ struct dimension_multiply_impl { template struct dimension_multiply_impl { - using type = downcast>; + using type = downcast>; }; } // namespace detail @@ -360,7 +384,7 @@ struct dimension_sqrt_impl>> { template struct dimension_sqrt_impl { - using type = dimension_sqrt_impl; + using type = dimension_sqrt_impl; }; template @@ -371,7 +395,7 @@ struct dimension_sqrt_impl> { } // namespace detail template -using dimension_sqrt = detail::dimension_sqrt_impl::type; +using dimension_sqrt = detail::dimension_sqrt_impl::type; // dimension_pow namespace detail { diff --git a/src/include/units/math.h b/src/include/units/math.h index be9274cd..ae13cf2a 100644 --- a/src/include/units/math.h +++ b/src/include/units/math.h @@ -39,7 +39,7 @@ namespace units { { using dim = dimension_pow; using r = ratio_pow; - return quantity>, Rep>(static_cast(std::pow(q.count(), N))); + return quantity>, Rep>(static_cast(std::pow(q.count(), N))); } template @@ -47,7 +47,7 @@ namespace units { { using dim = dimension_sqrt; using r = ratio_sqrt; - return quantity>, Rep>(static_cast(std::sqrt(q.count()))); + return quantity>, Rep>(static_cast(std::sqrt(q.count()))); } } // namespace units diff --git a/src/include/units/physical/dimensions.h b/src/include/units/physical/dimensions.h index 7945dc8b..26959f89 100644 --- a/src/include/units/physical/dimensions.h +++ b/src/include/units/physical/dimensions.h @@ -35,7 +35,7 @@ template typename DimTemplate> concept DimensionOf = (Dimension || BaseDimension) && is_derived_from_instantiation; template typename DimTemplate> -concept QuantityOf = Quantity && is_derived_from_instantiation; +concept QuantityOf = Quantity && is_derived_from_instantiation; // ------------------------ base dimensions ----------------------------- diff --git a/src/include/units/dimensions/acceleration.h b/src/include/units/physical/si/acceleration.h similarity index 62% rename from src/include/units/dimensions/acceleration.h rename to src/include/units/physical/si/acceleration.h index 891ad786..9a31f537 100644 --- a/src/include/units/dimensions/acceleration.h +++ b/src/include/units/physical/si/acceleration.h @@ -22,23 +22,23 @@ #pragma once -#include +#include +#include -namespace units { +namespace units::si { - struct acceleration : derived_dimension, exp> {}; +struct metre_per_second_sq : unit {}; +struct dim_acceleration : physical::dim_acceleration {}; - template - concept Acceleration = QuantityOf; +template +using acceleration = quantity; - struct metre_per_second_sq : coherent_derived_unit {}; +inline namespace literals { - inline namespace literals { +// mps_sq +constexpr auto operator""mps_sq(unsigned long long l) { return acceleration(l); } +constexpr auto operator""mps_sq(long double l) { return acceleration(l); } - // mps_sq - constexpr auto operator""mps_sq(unsigned long long l) { return quantity(l); } - constexpr auto operator""mps_sq(long double l) { return quantity(l); } +} // namespace literals - } // namespace literals - -} // namespace units +} // namespace units::si diff --git a/src/include/units/physical/si/length.h b/src/include/units/physical/si/length.h index bd9c27df..5143ba10 100644 --- a/src/include/units/physical/si/length.h +++ b/src/include/units/physical/si/length.h @@ -58,10 +58,10 @@ constexpr auto operator"" km(long double l) { return length, metre> {}; -struct foot : scaled_unit, yard> {}; -struct inch : scaled_unit, foot> {}; -struct mile : scaled_unit, yard> {}; +struct yard : named_scaled_unit, metre> {}; +struct foot : named_scaled_unit, yard> {}; +struct inch : named_scaled_unit, foot> {}; +struct mile : named_scaled_unit, yard> {}; inline namespace literals { diff --git a/src/include/units/physical/si/time.h b/src/include/units/physical/si/time.h index 0e1b409e..56534eba 100644 --- a/src/include/units/physical/si/time.h +++ b/src/include/units/physical/si/time.h @@ -31,8 +31,8 @@ struct second : named_unit {}; struct nanosecond : prefixed_unit {}; struct microsecond : prefixed_unit {}; struct millisecond : prefixed_unit {}; -struct minute : scaled_unit, second> {}; -struct hour : scaled_unit, second> {}; +struct minute : named_scaled_unit, second> {}; +struct hour : named_scaled_unit, second> {}; struct dim_time : physical::dim_time {}; diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 7b62210b..b9d64bf5 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -74,7 +74,7 @@ struct common_quantity_impl, quantity, Rep> { template struct common_quantity_impl, quantity, Rep> { using type = quantity< - D, downcast>>, + D, downcast>>, Rep>; }; @@ -154,7 +154,7 @@ template { using c_ratio = ratio_divide; using c_rep = std::common_type_t; - using ret_unit = downcast>; + using ret_unit = downcast>; using ret = quantity; using cast = detail::quantity_cast_impl; return cast::cast(q); @@ -410,7 +410,7 @@ public: template friend std::basic_ostream& operator<<(std::basic_ostream& os, const quantity& q) { - return os; // << q.count() << " " << detail::unit_text(); + return os << q.count(); // << " " << detail::unit_text(); TODO add support } }; @@ -466,7 +466,7 @@ template; using ratio = ratio_multiply; - using unit = downcast>; + using unit = detail::unit_for_dimension; using common_rep = decltype(lhs.count() * rhs.count()); using ret = quantity; return ret(lhs.count() * rhs.count()); @@ -480,7 +480,7 @@ template using dim = dim_invert; using ratio = ratio; - using unit = downcast>; + using unit = detail::unit_for_dimension; using common_rep = decltype(v / q.count()); using ret = quantity; return ret(v / q.count()); @@ -518,8 +518,8 @@ template; - using unit = downcast>>; + using ratio = ratio_divide; + using unit = detail::unit_for_dimension; using ret = quantity; return ret(lhs.count() / rhs.count()); } diff --git a/src/include/units/unit.h b/src/include/units/unit.h index 09ab02f8..6f7342ca 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -32,31 +32,35 @@ namespace units { -namespace detail { - -template -struct reference_unit : downcast_base> { +// scaled_unit +template +struct scaled_unit : downcast_base> { using reference = U; using ratio = R; }; -} // namespace detail - // UnitOf +namespace detail { + +template +concept SameReference = std::same_as; + +} + template concept UnitOf = Unit && Dimension && - std::same_as; + (std::same_as || detail::SameReference); namespace detail { -// same_reference_units +// same_scaled_units template -inline constexpr bool same_reference_units = false; +inline constexpr bool same_scaled_units = false; template -inline constexpr bool same_reference_units, Us...> = (UnitOf && ...); +inline constexpr bool same_scaled_units, Us...> = (UnitOf && ...); // deduced_unit template @@ -91,7 +95,7 @@ struct derived_ratio, U, URest...> { template using deduced_unit = - reference_unit::ratio>; + scaled_unit::ratio>; } // namespace detail @@ -112,7 +116,7 @@ using deduced_unit = * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) */ template -struct unit : downcast_child>> { +struct unit : downcast_child>> { static constexpr bool is_named = false; using prefix_type = no_prefix; }; @@ -130,7 +134,7 @@ struct unit : downcast_child>> { * @tparam PT no_prefix or a type of prefix family */ template -struct named_unit : downcast_child>> { +struct named_unit : downcast_child>> { static constexpr bool is_named = true; static constexpr auto symbol = Symbol; using prefix_type = PT; @@ -150,8 +154,8 @@ struct named_unit : downcast_child * @tparam R a scale to apply to U * @tparam U a reference unit to scale */ -template -struct scaled_unit : downcast_child>> { +template +struct named_scaled_unit : downcast_child>> { static constexpr bool is_named = true; static constexpr auto symbol = Symbol; using prefix_type = PT; @@ -171,11 +175,11 @@ struct scaled_unit : downcast_child requires std::same_as // TODO replace with the below code when gcc will stop to crash on it ;-) -// struct prefixed_unit : scaled_unit, // typename U::reference> {}; struct prefixed_unit : - downcast_child>> { + downcast_child>> { static constexpr bool is_named = true; static constexpr auto symbol = P::symbol + U::symbol; using prefix_type = P::prefix_type; @@ -194,7 +198,7 @@ struct prefixed_unit : * @tparam URest the units for the rest of dimensions from the recipe */ template - requires detail::same_reference_units && + requires detail::same_scaled_units && (U::is_named && (URest::is_named && ... && true)) struct deduced_unit : downcast_child> { static constexpr bool is_named = false; diff --git a/test/metabench/make_dimension/dimension_concepts_all.h b/test/metabench/make_dimension/dimension_concepts_all.h index f3293ccd..755da1e1 100644 --- a/test/metabench/make_dimension/dimension_concepts_all.h +++ b/test/metabench/make_dimension/dimension_concepts_all.h @@ -131,7 +131,7 @@ namespace units { struct dim_invert> : std::type_identity...>>> {}; template - using dim_invert_t = dim_invert::type; + using dim_invert_t = dim_invert::type; // make_dimension @@ -196,7 +196,7 @@ namespace units { struct dimension_multiply, dimension> : std::type_identity, dimension>>> {}; template - using dimension_multiply_t = dimension_multiply::type; + using dimension_multiply_t = dimension_multiply::type; // dimension_divide @@ -209,6 +209,6 @@ namespace units { }; template - using dimension_divide_t = dimension_divide::type; + using dimension_divide_t = dimension_divide::type; } // namespace units diff --git a/test/metabench/make_dimension/dimension_concepts_iface.h b/test/metabench/make_dimension/dimension_concepts_iface.h index d262e562..ca104c0d 100644 --- a/test/metabench/make_dimension/dimension_concepts_iface.h +++ b/test/metabench/make_dimension/dimension_concepts_iface.h @@ -131,7 +131,7 @@ namespace units { struct dim_invert> : std::type_identity...>>> {}; template - using dim_invert_t = dim_invert::type; + using dim_invert_t = dim_invert::type; // make_dimension @@ -196,7 +196,7 @@ namespace units { struct dimension_multiply, dimension> : std::type_identity, dimension>>> {}; template - using dimension_multiply_t = dimension_multiply::type; + using dimension_multiply_t = dimension_multiply::type; // dimension_divide @@ -209,6 +209,6 @@ namespace units { }; template - using dimension_divide_t = dimension_divide::type; + using dimension_divide_t = dimension_divide::type; } // namespace units diff --git a/test/metabench/make_dimension/dimension_no_concepts.h b/test/metabench/make_dimension/dimension_no_concepts.h index 188f92f8..ac8f8688 100644 --- a/test/metabench/make_dimension/dimension_no_concepts.h +++ b/test/metabench/make_dimension/dimension_no_concepts.h @@ -102,7 +102,7 @@ namespace units { struct dim_invert> : std::type_identity...>>> {}; template - using dim_invert_t = dim_invert::type; + using dim_invert_t = dim_invert::type; // make_dimension @@ -167,7 +167,7 @@ namespace units { struct dimension_multiply, dimension> : std::type_identity, dimension>>> {}; template - using dimension_multiply_t = dimension_multiply::type; + using dimension_multiply_t = dimension_multiply::type; // dimension_divide @@ -180,6 +180,6 @@ namespace units { }; template - using dimension_divide_t = dimension_divide::type; + using dimension_divide_t = dimension_divide::type; } // namespace units diff --git a/test/metabench/make_dimension/downcasting_concepts_all.h b/test/metabench/make_dimension/downcasting_concepts_all.h index db0c3b3b..68bd5230 100644 --- a/test/metabench/make_dimension/downcasting_concepts_all.h +++ b/test/metabench/make_dimension/downcasting_concepts_all.h @@ -29,18 +29,18 @@ namespace units { template struct downcast_base { - using base_type = BaseType; + using downcast_base_type = BaseType; }; template concept Downcastable = requires { - typename T::base_type; + typename T::downcast_base_type; } && - std::derived_from>; + std::derived_from>; template - using downcast_base_t = T::base_type; + using downcast_base_t = T::downcast_base_type; template struct downcast_traits : std::type_identity {}; diff --git a/test/metabench/make_dimension/downcasting_no_concepts.h b/test/metabench/make_dimension/downcasting_no_concepts.h index 519c469d..051b0ff5 100644 --- a/test/metabench/make_dimension/downcasting_no_concepts.h +++ b/test/metabench/make_dimension/downcasting_no_concepts.h @@ -29,11 +29,11 @@ namespace units { template struct downcast_base { - using base_type = BaseType; + using downcast_base_type = BaseType; }; template - using downcast_base_t = T::base_type; + using downcast_base_t = T::downcast_base_type; template struct downcast_traits : std::type_identity {}; diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index ff029a5f..3636cf32 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -109,10 +109,10 @@ using namespace units::si; // class invariants -// constexpr quantity q(1); // should not compile -// constexpr quantity> error(0m); // should trigger a static_assert -// constexpr quantity error(0); // should trigger a static_assert -// constexpr quantity>, int> error(0); // should trigger a static_assert +// constexpr quantity error(0); // should not compile (unit of a different dimension) +// constexpr quantity> error(0); // should not compile (quantity used as Rep) +// constexpr quantity error(0); // should not compile (reordered arguments) +// constexpr quantity>, int> error(0); // should not compile (negative unit ratio) // member types @@ -134,9 +134,9 @@ static_assert(length(km).count() == km.count()); static_assert(length(1).count() == 1); static_assert(length(my_value(1)).count() == 1); static_assert(length(1).count() == my_int{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); // should not compile (truncating conversion) +// static_assert(length(my_value(1.0)).count() == 1); // should not compile (truncating conversion) +// static_assert(length(1.0).count() == my_int{1}); // should not compile (truncating conversion) 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); @@ -147,27 +147,23 @@ static_assert(length(1).count() == my_double{1.0}); static_assert(length(3.14).count() == my_double{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 (truncating conversion) static_assert(length(quantity_cast>(3.14m)).count() == 3); -// static_assert(length(length(1000.0)).count() == 1000); // should not compile -// static_assert(length(1000.0m).count() == 1000); // should not compile +// static_assert(length(length(1000.0)).count() == 1000); // should not compile (truncating conversion) +// static_assert(length(1000.0m).count() == my_int{1000}); // should not compile (truncating conversion) static_assert(length(1000.0m).count() == 1000.0); static_assert(length(length(1000.0)).count() == 1000.0); static_assert(length(1000.0m).count() == my_double{1000.0}); static_assert(length(km).count() == 1000.0); static_assert(length(km).count() == my_double{1000.0}); static_assert(length(1km).count() == 1000); -// static_assert(length(1_s).count() == 1); // should not compile -// static_assert(length(1010m).count() == 1); // should not compile +// static_assert(length(1s).count() == 1); // should not compile (different dimensions) +//static_assert(length(1010m).count() == 1); // should not compile (truncating conversion) static_assert(length(quantity_cast>(1010m)).count() == 1); // assignment operator -static_assert([]() { - length l1(1), l2(2); - return l2 = l1; -}() - .count() == 1); +static_assert([]() { length l1(1), l2(2); return l2 = l1; }().count() == 1); // static member functions @@ -218,13 +214,13 @@ static_assert((1m *= 2).count() == 2); static_assert((2m /= 2).count() == 1); static_assert((7m %= 2).count() == 1); static_assert((7m %= 2m).count() == 1); -// static_assert((7.m %= 2.).count() == 1); // should not compile -// static_assert((7.m %= 2).count() == 1); // should not compile -// static_assert((7m %= 2.).count() == 1); // should not compile +// static_assert((7.m %= 2.).count() == 1); // should not compile (operation not allowed for floating-point types) +// static_assert((7.m %= 2).count() == 1); // should not compile (operation not allowed for floating-point types) +// static_assert((7m %= 2.).count() == 1); // should not compile (operation not allowed for floating-point types) static_assert((7m %= 2m).count() == 1); -// static_assert((7.m %= 2.m).count() == 1); // should not compile -// static_assert((7.m %= 2m).count() == 1); // should not compile -// static_assert((7m %= 2.m).count() == 1); // should not compile +// static_assert((7.m %= 2.m).count() == 1); // should not compile (operation not allowed for floating-point types) +// static_assert((7.m %= 2m).count() == 1); // should not compile (operation not allowed for floating-point types) +// static_assert((7m %= 2.m).count() == 1); // should not compile (operation not allowed for floating-point types) // non-member arithmetic operators @@ -239,13 +235,27 @@ static_assert(std::is_same_v() * 1.0), length()), length>); static_assert( std::is_same_v() * si::time()), length>); +static_assert( + std::is_same_v() * si::time()), length>, int>>); +// TODO uncomment below when fixed in gcc +// static_assert(std::is_same_v() * si::time()), +// quantity, exp>, scaled_unit>>>); static_assert(std::is_same_v()), frequency>); +static_assert(std::is_same_v()), frequency>, int>>); static_assert(std::is_same_v()), si::time>); +// TODO uncomment below when fixed in gcc +// static_assert(std::is_same_v()), +// quantity>, scaled_unit>>>); static_assert(std::is_same_v() / 1.0), length>); static_assert(std::is_same_v() / length()), double>); static_assert(std::is_same_v() / length()), double>); static_assert( std::is_same_v() / si::time()), velocity>); +static_assert( + std::is_same_v() / si::time()), velocity>>>); +// TODO uncomment below when fixed in gcc +// static_assert(std::is_same_v() / length()), +// quantity, exp>, scaled_unit>>>); static_assert(std::is_same_v() % short(1)), length>); static_assert(std::is_same_v() % length(1)), length>); @@ -307,15 +317,18 @@ static_assert(std::is_same_v, lengt // quantity_cast -static_assert(std::is_same_v>>(2km))::unit, metre>); +static_assert(std::is_same_v>>(2km))::unit, metre>); -// static_assert(quantity_cast(2km).count() == 2000); // should not compile static_assert(quantity_cast>(2km).count() == 2000); static_assert(quantity_cast>(2000m).count() == 2); +static_assert(quantity_cast>(1.23m).count() == 1); +static_assert(quantity_cast(2km).count() == 2000); +static_assert(quantity_cast(2000m).count() == 2); +static_assert(quantity_cast(1.23m).count() == 1); // time -// static_assert(1s == 1m); // should not compile +// static_assert(1s == 1m); // should not compile (different dimensions) static_assert(1h == 3600s); // length diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index 00172c9a..58eb8e9c 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -30,23 +30,23 @@ using namespace units; struct metre : named_unit {}; struct centimetre : prefixed_unit {}; struct kilometre : prefixed_unit {}; -struct yard : scaled_unit, metre> {}; -struct foot : scaled_unit, yard> {}; +struct yard : named_scaled_unit, metre> {}; +struct foot : named_scaled_unit, yard> {}; struct dim_length : base_dimension<"length", metre> {}; struct second : named_unit {}; -struct hour : scaled_unit, second> {}; +struct hour : named_scaled_unit, second> {}; struct dim_time : base_dimension<"time", second> {}; struct metre_per_second : unit {}; struct dim_velocity : derived_dimension, exp> {}; struct kilometre_per_hour : deduced_unit {}; -static_assert(std::is_same_v>>, metre>); -static_assert(std::is_same_v>>, centimetre>); -static_assert(std::is_same_v>>, yard>); -static_assert(std::is_same_v>>>, foot>); -static_assert(std::is_same_v>>, kilometre_per_hour>); +static_assert(std::is_same_v>>, metre>); +static_assert(std::is_same_v>>, centimetre>); +static_assert(std::is_same_v>>, yard>); +static_assert(std::is_same_v>>>, foot>); +static_assert(std::is_same_v>>, kilometre_per_hour>); static_assert(centimetre::symbol == "cm"); static_assert(kilometre::symbol == "km");