diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 120000 index 7a7656e8..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -docs/CHANGELOG.md \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/design/quantity.rst b/docs/design/quantity.rst index 91c8dacc..092a2535 100644 --- a/docs/design/quantity.rst +++ b/docs/design/quantity.rst @@ -11,7 +11,7 @@ Interface The difference is that it uses ``double`` as a default representation and has a few additional member types and functions:: - template U, ScalableNumber Rep = double> + template U, QuantityValue Rep = double> class quantity { public: using dimension = D; @@ -27,7 +27,7 @@ a few additional member types and functions:: [[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs); - template + template requires std::magma [[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity& q); diff --git a/docs/framework/constants.rst b/docs/framework/constants.rst index 0b19539f..47bdb9be 100644 --- a/docs/framework/constants.rst +++ b/docs/framework/constants.rst @@ -18,7 +18,7 @@ For example the speed of light constant in :term:`SI` is defined as:: namespace si::si2019 { - template + template inline constexpr auto speed_of_light = speed(299792458); } @@ -27,7 +27,7 @@ The same constant defined for natural units may be provided as:: namespace natural { - template + template inline constexpr auto speed_of_light = speed(1); } diff --git a/docs/framework/dimensions.rst b/docs/framework/dimensions.rst index 34769eeb..98004b52 100644 --- a/docs/framework/dimensions.rst +++ b/docs/framework/dimensions.rst @@ -58,8 +58,8 @@ dimension, than we will end up with just a scalable number type: Time auto dur1 = 10_q_s; Time auto dur2 = 2_q_s; Frequency auto fr1 = 5_q_Hz; - ScalableNumber auto v1 = dur1 / dur2; // 5 - ScalableNumber auto v2 = dur1 * fr1; // 50 + QuantityValue auto v1 = dur1 / dur2; // 5 + QuantityValue auto v2 = dur1 * fr1; // 50 Quantity points have a more restricted set of operations. Quantity points can't be added together, diff --git a/docs/framework/quantities.rst b/docs/framework/quantities.rst index c2c675af..116ddbad 100644 --- a/docs/framework/quantities.rst +++ b/docs/framework/quantities.rst @@ -34,7 +34,7 @@ type to ``double`` by default:: namespace si { - template + template using length = quantity; } @@ -75,7 +75,7 @@ be used:: All instances of `quantity` class always match the `Quantity` concept. All other regular types that are not quantities are called :term:`scalable numbers ` by the library and match the - `ScalableNumber` concept. + `QuantityValue` concept. However, the above is not the most important usage of those concepts. Let's assume that the user wants to implement an ``avg_speed`` function that will @@ -185,7 +185,7 @@ are provided:: template concept Dimensionless = QuantityOf; - template + template using dimensionless = quantity; There are two special units provided for usage with such a quantity: diff --git a/docs/reference/core/concepts.rst b/docs/reference/core/concepts.rst index 8ebf8b91..103d1b41 100644 --- a/docs/reference/core/concepts.rst +++ b/docs/reference/core/concepts.rst @@ -63,7 +63,7 @@ Concepts satisfy :expr:`Quantity` recursively (i.e. ``std::optional>``). -.. concept:: template ScalableNumber +.. concept:: template QuantityValue A concept matching non-Quantity types. Satisfied by types that match :expr:`(!Quantity) && (!WrappedQuantity) && std::regular` and satisfy one of the diff --git a/docs/use_cases/custom_representation_types.rst b/docs/use_cases/custom_representation_types.rst index dce853fe..a88d7b27 100644 --- a/docs/use_cases/custom_representation_types.rst +++ b/docs/use_cases/custom_representation_types.rst @@ -9,11 +9,11 @@ its own custom logic for it (i.e. use a complex number or a measurement class th not only a value but also a measurement error). -A `ScalableNumber` concept +A `QuantityValue` concept -------------------------- To support a minimum set of `quantity` operations all custom representation types have to -satisfy at least the `ScalableNumber` concept. Which means that they: +satisfy at least the `QuantityValue` concept. Which means that they: - cannot be quantities by themselves, - cannot be wrappers over the `quantity` type (i.e. ``std::optional>``), @@ -101,7 +101,7 @@ The only difference here is that in this case we have to explicitly cast the `qu Additional Requirements ----------------------- -As noted in the previous chapter, the `ScalableNumber` concept guarantees us the possibility +As noted in the previous chapter, the `QuantityValue` concept guarantees us the possibility to construct quantities, convert between the units of the same dimension, and compare them for equality. To provide additional `quantity` operations the custom representation type have to satisfy more requirements. @@ -200,7 +200,7 @@ The `quantity` class template has a few static member functions: `quantity::zero representation type. The default implementation is provided through the `quantity_values` class template:: - template + template struct quantity_values { static constexpr Rep zero() noexcept { return Rep(0); } static constexpr Rep one() noexcept { return Rep(1); } @@ -220,7 +220,7 @@ library's framework treat floating-point representation types differently than t ones. This behavior can also be extended to the custom representation types with `treat_as_floating_point` customization point which default definition is:: - template + template inline constexpr bool treat_as_floating_point = std::is_floating_point_v; If our representation type should have a floating-point semantics or if it is a class diff --git a/docs/use_cases/extensions.rst b/docs/use_cases/extensions.rst index 6a85c5da..6ec9a266 100644 --- a/docs/use_cases/extensions.rst +++ b/docs/use_cases/extensions.rst @@ -121,7 +121,7 @@ coherent unit:: struct desk_per_hour : deduced_unit {}; // a quantity of our dimension - template + template U, QuantityValue Rep = double> using desk_rate = quantity; // a concept matching the above quantity @@ -150,7 +150,7 @@ define a new base dimension, its units, quantity helper, concept, and UDLs:: struct person : named_unit {}; struct dim_people : base_dimension<"people", person> {}; - template + template U, QuantityValue Rep = double> using people = quantity; template @@ -169,7 +169,7 @@ With the above we can now define a new derived dimension:: struct person_per_desk : deduced_unit {}; - template + template U, QuantityValue Rep = double> using occupancy_rate = quantity; template @@ -216,7 +216,7 @@ Such units do not share their references with base units of other systems: struct dim_length : base_dimension<"L", foot> {}; - template + template U, QuantityValue Rep = double> using length = quantity; } // namespace fps @@ -236,7 +236,7 @@ different systems: struct dim_length : base_dimension<"L", metre> {}; - template + template U, QuantityValue Rep = double> using length = quantity; namespace fps { @@ -246,7 +246,7 @@ different systems: struct dim_length : base_dimension<"L", foot> {}; - template + template U, QuantityValue Rep = double> using length = quantity; } // namespace fps diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index 2dab1082..d4e73e24 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -33,7 +33,7 @@ struct yard : named_scaled_unit {}; struct dim_length : base_dimension<"L", foot> {}; -template +template U, QuantityValue Rep = double> using length = quantity; } // namespace fps @@ -45,7 +45,7 @@ struct kilometre : prefixed_unit {} struct dim_length : base_dimension<"L", metre> {}; -template +template U, QuantityValue Rep = double> using length = quantity; namespace fps { @@ -55,7 +55,7 @@ struct yard : named_scaled_unit {}; struct dim_length : base_dimension<"L", foot> {}; -template +template U, QuantityValue Rep = double> using length = quantity; } // namespace fps diff --git a/example/glide_computer.cpp b/example/glide_computer.cpp index 8d2c726b..dc17d878 100644 --- a/example/glide_computer.cpp +++ b/example/glide_computer.cpp @@ -87,7 +87,7 @@ public: } template - requires (ScalableNumber || Dimensionless) + requires (QuantityValue || Dimensionless) [[nodiscard]] friend constexpr auto operator*(const vector& lhs, const V& value) requires requires { lhs.magnitude() * value; } { @@ -95,7 +95,7 @@ public: } template - requires (ScalableNumber || Dimensionless) + requires (QuantityValue || Dimensionless) [[nodiscard]] friend constexpr auto operator*(const V& value, const vector& rhs) requires requires { value * rhs.magnitude(); } { diff --git a/example/linear_algebra.cpp b/example/linear_algebra.cpp index fabbe13d..6dfe06c9 100644 --- a/example/linear_algebra.cpp +++ b/example/linear_algebra.cpp @@ -200,10 +200,10 @@ void matrix_of_quantity_tests() matrix_of_quantity_divide_by_scalar(); } -template +template using length_v = si::length>; -template +template using force_v = si::force>; void quantity_of_vector_add() @@ -273,7 +273,7 @@ void quantity_of_vector_tests() quantity_of_vector_divide_by_scalar(); } -template +template using length_m = si::length>; void quantity_of_matrix_add() diff --git a/example/measurement.cpp b/example/measurement.cpp index 20269ac8..2ab40053 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -114,15 +114,13 @@ private: value_type uncertainty_{}; }; -static_assert(units::ScalableNumber>); - } // namespace -template -inline constexpr bool units::treat_as_floating_point> = std::is_floating_point_v; namespace { +static_assert(units::QuantityValue>); + void example() { using namespace units::physical; diff --git a/src/include/units/bits/basic_concepts.h b/src/include/units/bits/basic_concepts.h index 70281ae2..242f5a8a 100644 --- a/src/include/units/bits/basic_concepts.h +++ b/src/include/units/bits/basic_concepts.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,34 @@ template concept QuantityPoint = detail::is_quantity_point; +// QuantityValue + +template +concept common_type_with_ = + std::same_as, std::common_type_t> && + std::constructible_from, T> && + std::constructible_from, U>; + +template +concept scalable_number_ = // exposition only + std::regular_invocable, T, U> && + std::regular_invocable, T, U>; + +template +concept castable_number_ = // exposition only + common_type_with_ && + scalable_number_>; + +template +concept scalable_ = // exposition only + castable_number_ || + (requires { typename T::value_type; } && castable_number_ && scalable_number_>); + +template +concept scalable_with_ = // exposition only + common_type_with_ && + scalable_>; + // WrappedQuantity namespace detail { @@ -248,31 +277,8 @@ inline constexpr bool is_wrapped_quantity = Quantity * recursively (i.e. `std::optional>`). */ template -concept WrappedQuantity = detail::is_wrapped_quantity; - -// ScalableNumber - -namespace detail { - -template -concept constructible_from_integral = - // construction from an integral type - std::constructible_from && - // unit scaling - std::regular_invocable, T, T> && - std::regular_invocable, T, T>; - -template -concept not_constructible_from_integral = - // not construction from an integral type - (!std::constructible_from) && - - // scaling by the value from ratio - std::regular_invocable, T, std::int64_t> && - std::regular_invocable, std::int64_t, T>; // && - // std::regular_invocable, T, std::int64_t>; // TODO Uncomment when a bug in LA is fixed - -} // namespace detail +concept wrapped_quantity_ = // exposition only + detail::is_wrapped_quantity; /** * @brief A concept matching non-Quantity types. @@ -280,10 +286,10 @@ concept not_constructible_from_integral = * Satisfied by types that satisfy `(!Quantity) && (!WrappedQuantity) && std::regular`. */ template -concept ScalableNumber = +concept QuantityValue = (!Quantity) && - (!WrappedQuantity) && + (!wrapped_quantity_) && std::regular && - (detail::constructible_from_integral || detail::not_constructible_from_integral); + scalable_; } // namespace units diff --git a/src/include/units/bits/common_quantity.h b/src/include/units/bits/common_quantity.h index 570d26d3..00c4b2b3 100644 --- a/src/include/units/bits/common_quantity.h +++ b/src/include/units/bits/common_quantity.h @@ -28,10 +28,10 @@ namespace units { -template U, ScalableNumber Rep> +template U, QuantityValue Rep> class quantity; -template U, ScalableNumber Rep> +template U, QuantityValue Rep> class quantity_point; namespace detail { @@ -70,8 +70,7 @@ quantity_point common_quantity_point_impl(quantity); } // namespace detail -template> - requires equivalent +template Q2, QuantityValue Rep = std::common_type_t> using common_quantity = TYPENAME detail::common_quantity_impl::type; template diff --git a/src/include/units/bits/quantity_of.h b/src/include/units/bits/quantity_of.h index 04191d4d..27841311 100644 --- a/src/include/units/bits/quantity_of.h +++ b/src/include/units/bits/quantity_of.h @@ -73,7 +73,10 @@ concept QuantityOfT = Quantity && DimensionOfT -concept QuantityOf = Quantity && Dimension && equivalent; +template +concept QuantityOf = Quantity && Dimension && equivalent; + +template +concept QuantityEquivalentTo = Quantity && QuantityOf; } // namespace units diff --git a/src/include/units/customization_points.h b/src/include/units/customization_points.h index 4a9f0dc2..27b97fc5 100644 --- a/src/include/units/customization_points.h +++ b/src/include/units/customization_points.h @@ -22,7 +22,6 @@ #pragma once -#include #include #include @@ -37,9 +36,13 @@ namespace units { * * @tparam Rep a representation type for which a type trait is defined */ -template +template inline constexpr bool treat_as_floating_point = std::is_floating_point_v; +template + requires requires { typename T::value_type; } +inline constexpr bool treat_as_floating_point = treat_as_floating_point; + /** * @brief A type trait that defines zero, one, min, and max for a representation type * @@ -49,7 +52,7 @@ inline constexpr bool treat_as_floating_point = std::is_floating_point_v; * * @tparam Rep a representation type for which a type trait is defined */ -template +template struct quantity_values { static constexpr Rep zero() noexcept { return Rep(0); } static constexpr Rep one() noexcept { return Rep(1); } diff --git a/src/include/units/data/base/information.h b/src/include/units/data/base/information.h index 89846916..ebe28152 100644 --- a/src/include/units/data/base/information.h +++ b/src/include/units/data/base/information.h @@ -48,7 +48,7 @@ struct dim_information : base_dimension<"information", bit> {}; template concept Information = QuantityOf; -template +template U, QuantityValue Rep = double> using information = quantity; inline namespace literals { diff --git a/src/include/units/data/derived/bitrate.h b/src/include/units/data/derived/bitrate.h index 9b844437..94cbf166 100644 --- a/src/include/units/data/derived/bitrate.h +++ b/src/include/units/data/derived/bitrate.h @@ -41,7 +41,7 @@ struct pebibit_per_second : deduced_unit concept Bitrate = QuantityOf; -template +template U, QuantityValue Rep = double> using bitrate = quantity; inline namespace literals { diff --git a/src/include/units/generic/angle.h b/src/include/units/generic/angle.h index f35798a4..d52274bb 100644 --- a/src/include/units/generic/angle.h +++ b/src/include/units/generic/angle.h @@ -35,7 +35,7 @@ struct dim_angle : base_dimension<"A", U> {}; template concept Angle = QuantityOfT; -template +template> U, QuantityValue Rep = double> using angle = quantity, U, Rep>; inline namespace literals { diff --git a/src/include/units/generic/dimensionless.h b/src/include/units/generic/dimensionless.h index 14aba730..021135fb 100644 --- a/src/include/units/generic/dimensionless.h +++ b/src/include/units/generic/dimensionless.h @@ -40,7 +40,7 @@ struct dim_one : derived_dimension {}; template concept Dimensionless = QuantityOf; -template +template U, QuantityValue Rep = double> using dimensionless = quantity; } // namespace units diff --git a/src/include/units/physical/natural/bits/dimensions.h b/src/include/units/physical/natural/bits/dimensions.h index d589fa4b..2067ecbf 100644 --- a/src/include/units/physical/natural/bits/dimensions.h +++ b/src/include/units/physical/natural/bits/dimensions.h @@ -29,35 +29,35 @@ namespace units::physical::natural { struct dim_length : physical::dim_length {}; -template +template U, QuantityValue Rep = double> using length = quantity; struct dim_time : physical::dim_time {}; -template +template U, QuantityValue Rep = double> using time = quantity; struct dim_mass : physical::dim_mass {}; -template +template U, QuantityValue Rep = double> using mass = quantity; struct dim_speed : physical::dim_speed {}; -template +template U, QuantityValue Rep = double> using speed = quantity; struct dim_acceleration : physical::dim_acceleration {}; -template +template U, QuantityValue Rep = double> using acceleration = quantity; struct dim_force : physical::dim_force {}; -template +template U, QuantityValue Rep = double> using force = quantity; struct dim_momentum : physical::dim_momentum {}; -template +template U, QuantityValue Rep = double> using momentum = quantity; struct dim_energy : physical::dim_energy {}; -template +template U, QuantityValue Rep = double> using energy = quantity; // Typical UDLs will not work here as the same units are reused by many quantities. diff --git a/src/include/units/physical/natural/constants.h b/src/include/units/physical/natural/constants.h index 743a706a..43f3c961 100644 --- a/src/include/units/physical/natural/constants.h +++ b/src/include/units/physical/natural/constants.h @@ -26,7 +26,7 @@ namespace units::physical::natural { -template +template inline constexpr auto speed_of_light = speed(1); } // namespace units::physical::natural diff --git a/src/include/units/physical/si/base/amount_of_substance.h b/src/include/units/physical/si/base/amount_of_substance.h index 17a42658..1cdea8d0 100644 --- a/src/include/units/physical/si/base/amount_of_substance.h +++ b/src/include/units/physical/si/base/amount_of_substance.h @@ -32,7 +32,7 @@ struct mole : named_unit {}; struct dim_amount_of_substance : physical::dim_amount_of_substance {}; -template +template U, QuantityValue Rep = double> using amount_of_substance = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/base/electric_current.h b/src/include/units/physical/si/base/electric_current.h index b24d4f4d..efb46e97 100644 --- a/src/include/units/physical/si/base/electric_current.h +++ b/src/include/units/physical/si/base/electric_current.h @@ -52,7 +52,7 @@ struct yottaampere : prefixed_unit {}; struct dim_electric_current : physical::dim_electric_current {}; -template +template U, QuantityValue Rep = double> using electric_current = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/base/length.h b/src/include/units/physical/si/base/length.h index 477a4c68..ecc8ae84 100644 --- a/src/include/units/physical/si/base/length.h +++ b/src/include/units/physical/si/base/length.h @@ -54,7 +54,7 @@ struct astronomical_unit : named_scaled_unit {}; -template +template U, QuantityValue Rep = double> using length = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/base/luminous_intensity.h b/src/include/units/physical/si/base/luminous_intensity.h index 4ac111e4..e3726904 100644 --- a/src/include/units/physical/si/base/luminous_intensity.h +++ b/src/include/units/physical/si/base/luminous_intensity.h @@ -52,7 +52,7 @@ struct yottacandela : prefixed_unit {}; struct dim_luminous_intensity : physical::dim_luminous_intensity {}; -template +template U, QuantityValue Rep = double> using luminous_intensity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/base/mass.h b/src/include/units/physical/si/base/mass.h index 9f3fe0b1..3f99d4e4 100644 --- a/src/include/units/physical/si/base/mass.h +++ b/src/include/units/physical/si/base/mass.h @@ -76,7 +76,7 @@ struct dalton : named_scaled_unit {}; -template +template U, QuantityValue Rep = double> using mass = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/base/thermodynamic_temperature.h b/src/include/units/physical/si/base/thermodynamic_temperature.h index e2f6e147..0e7f251b 100644 --- a/src/include/units/physical/si/base/thermodynamic_temperature.h +++ b/src/include/units/physical/si/base/thermodynamic_temperature.h @@ -31,7 +31,7 @@ struct kelvin : named_unit {}; struct dim_thermodynamic_temperature : physical::dim_thermodynamic_temperature {}; -template +template U, QuantityValue Rep = double> using thermodynamic_temperature = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/base/time.h b/src/include/units/physical/si/base/time.h index a18d8413..1ab3f621 100644 --- a/src/include/units/physical/si/base/time.h +++ b/src/include/units/physical/si/base/time.h @@ -43,7 +43,7 @@ struct day : named_scaled_unit {}; struct dim_time : physical::dim_time {}; -template +template U, QuantityValue Rep = double> using time = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/base/length.h b/src/include/units/physical/si/cgs/base/length.h index 1ab6e0c5..40153b42 100644 --- a/src/include/units/physical/si/cgs/base/length.h +++ b/src/include/units/physical/si/cgs/base/length.h @@ -31,7 +31,7 @@ using si::centimetre; struct dim_length : physical::dim_length {}; -template +template U, QuantityValue Rep = double> using length = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/base/mass.h b/src/include/units/physical/si/cgs/base/mass.h index 6a4a30fd..b458cbf0 100644 --- a/src/include/units/physical/si/cgs/base/mass.h +++ b/src/include/units/physical/si/cgs/base/mass.h @@ -31,7 +31,7 @@ using si::gram; struct dim_mass : physical::dim_mass {}; -template +template U, QuantityValue Rep = double> using mass = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/acceleration.h b/src/include/units/physical/si/cgs/derived/acceleration.h index e4776469..d53cbb10 100644 --- a/src/include/units/physical/si/cgs/derived/acceleration.h +++ b/src/include/units/physical/si/cgs/derived/acceleration.h @@ -31,7 +31,7 @@ namespace units::physical::si::cgs { struct gal : named_unit {}; struct dim_acceleration : physical::dim_acceleration {}; -template +template U, QuantityValue Rep = double> using acceleration = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/area.h b/src/include/units/physical/si/cgs/derived/area.h index b812fcdc..cfa6bae2 100644 --- a/src/include/units/physical/si/cgs/derived/area.h +++ b/src/include/units/physical/si/cgs/derived/area.h @@ -32,7 +32,7 @@ using si::square_centimetre; struct dim_area : physical::dim_area {}; -template +template U, QuantityValue Rep = double> using area = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/energy.h b/src/include/units/physical/si/cgs/derived/energy.h index 045c696f..e540521d 100644 --- a/src/include/units/physical/si/cgs/derived/energy.h +++ b/src/include/units/physical/si/cgs/derived/energy.h @@ -33,7 +33,7 @@ struct erg : named_unit {}; struct dim_energy : physical::dim_energy {}; -template +template U, QuantityValue Rep = double> using energy = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/force.h b/src/include/units/physical/si/cgs/derived/force.h index 194bf77d..7b12ed8b 100644 --- a/src/include/units/physical/si/cgs/derived/force.h +++ b/src/include/units/physical/si/cgs/derived/force.h @@ -34,7 +34,7 @@ struct dyne : named_unit {}; struct dim_force : physical::dim_force {}; -template +template U, QuantityValue Rep = double> using force = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/power.h b/src/include/units/physical/si/cgs/derived/power.h index 06e84ce0..8f00acca 100644 --- a/src/include/units/physical/si/cgs/derived/power.h +++ b/src/include/units/physical/si/cgs/derived/power.h @@ -33,7 +33,7 @@ struct erg_per_second : unit {}; struct dim_power : physical::dim_power {}; -template +template U, QuantityValue Rep = double> using power = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/pressure.h b/src/include/units/physical/si/cgs/derived/pressure.h index 9f13f87c..63aef87e 100644 --- a/src/include/units/physical/si/cgs/derived/pressure.h +++ b/src/include/units/physical/si/cgs/derived/pressure.h @@ -34,7 +34,7 @@ struct barye : named_unit {}; struct dim_pressure : physical::dim_pressure {}; -template +template U, QuantityValue Rep = double> using pressure = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/cgs/derived/speed.h b/src/include/units/physical/si/cgs/derived/speed.h index 79f80d70..22ecb4df 100644 --- a/src/include/units/physical/si/cgs/derived/speed.h +++ b/src/include/units/physical/si/cgs/derived/speed.h @@ -32,7 +32,7 @@ namespace units::physical::si::cgs { struct centimetre_per_second : unit {}; struct dim_speed : physical::dim_speed {}; -template +template U, QuantityValue Rep = double> using speed = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/constants.h b/src/include/units/physical/si/constants.h index 0a2af419..b8e86595 100644 --- a/src/include/units/physical/si/constants.h +++ b/src/include/units/physical/si/constants.h @@ -32,31 +32,31 @@ namespace units::physical::si::si2019 { -template +template inline constexpr auto planck_constant = energy(6.62607015e-34) * time(1); -template +template inline constexpr auto reduced_planck_constant = energy(6.582119569e-10) * time(1); -template +template inline constexpr auto elementary_charge = electric_charge(1.602176634e-19); -template +template inline constexpr auto boltzmann_constant = energy(1.380649e-23) / temperature(1); -template +template inline constexpr auto avogadro_constant = Rep(6.02214076e23) / substance(1); -template +template inline constexpr auto speed_of_light = speed(299'792'458); -template +template inline constexpr auto hyperfine_structure_transition_frequency = frequency(9'192'631'770); -// template +// template // inline constexpr auto luminous_efficacy = 683_q_lm / 1_q_W; -template +template inline constexpr auto standard_gravity = acceleration(9.80665); } // namespace units::physical::si::si2019 diff --git a/src/include/units/physical/si/derived/absorbed_dose.h b/src/include/units/physical/si/derived/absorbed_dose.h index 9feb64d8..56d0df1f 100644 --- a/src/include/units/physical/si/derived/absorbed_dose.h +++ b/src/include/units/physical/si/derived/absorbed_dose.h @@ -53,7 +53,7 @@ struct yottagray : prefixed_unit {}; struct dim_absorbed_dose : physical::dim_absorbed_dose {}; -template +template U, QuantityValue Rep = double> using absorbed_dose = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/acceleration.h b/src/include/units/physical/si/derived/acceleration.h index ba75ca1e..20e6de33 100644 --- a/src/include/units/physical/si/derived/acceleration.h +++ b/src/include/units/physical/si/derived/acceleration.h @@ -31,7 +31,7 @@ namespace units::physical::si { struct metre_per_second_sq : unit {}; struct dim_acceleration : physical::dim_acceleration {}; -template +template U, QuantityValue Rep = double> using acceleration = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/angular_velocity.h b/src/include/units/physical/si/derived/angular_velocity.h index f4b56b7e..cd892f7c 100644 --- a/src/include/units/physical/si/derived/angular_velocity.h +++ b/src/include/units/physical/si/derived/angular_velocity.h @@ -34,7 +34,7 @@ struct radian_per_second : named_unit, dim_time> {}; -template +template U, QuantityValue Rep = double> using angular_velocity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/area.h b/src/include/units/physical/si/derived/area.h index 99a69d5f..152cb90b 100644 --- a/src/include/units/physical/si/derived/area.h +++ b/src/include/units/physical/si/derived/area.h @@ -54,7 +54,7 @@ struct square_yottametre : deduced_unit struct hectare : alias_unit {}; -template +template U, QuantityValue Rep = double> using area = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/capacitance.h b/src/include/units/physical/si/derived/capacitance.h index 6e3ca871..86373372 100644 --- a/src/include/units/physical/si/derived/capacitance.h +++ b/src/include/units/physical/si/derived/capacitance.h @@ -54,7 +54,7 @@ struct yottafarad : prefixed_unit {}; struct dim_capacitance : physical::dim_capacitance {}; -template +template U, QuantityValue Rep = double> using capacitance = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/catalytic_activity.h b/src/include/units/physical/si/derived/catalytic_activity.h index db5d296d..a82bbe2f 100644 --- a/src/include/units/physical/si/derived/catalytic_activity.h +++ b/src/include/units/physical/si/derived/catalytic_activity.h @@ -56,7 +56,7 @@ struct enzyme_unit : named_scaled_unit {}; -template +template U, QuantityValue Rep = double> using catalytic_activity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/charge_density.h b/src/include/units/physical/si/derived/charge_density.h index a3483936..4389d8fd 100644 --- a/src/include/units/physical/si/derived/charge_density.h +++ b/src/include/units/physical/si/derived/charge_density.h @@ -36,10 +36,10 @@ struct coulomb_per_metre_sq : unit {}; struct dim_charge_density : physical::dim_charge_density {}; struct dim_surface_charge_density : physical::dim_surface_charge_density {}; -template +template U, QuantityValue Rep = double> using charge_density = quantity; -template +template U, QuantityValue Rep = double> using surface_charge_density = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/concentration.h b/src/include/units/physical/si/derived/concentration.h index a8579247..9b3130ad 100644 --- a/src/include/units/physical/si/derived/concentration.h +++ b/src/include/units/physical/si/derived/concentration.h @@ -32,7 +32,7 @@ namespace units::physical::si { struct mol_per_metre_cub : unit {}; struct dim_concentration : physical::dim_concentration {}; -template +template U, QuantityValue Rep = double> using concentration = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/conductance.h b/src/include/units/physical/si/derived/conductance.h index a5fdf39c..db0d82c7 100644 --- a/src/include/units/physical/si/derived/conductance.h +++ b/src/include/units/physical/si/derived/conductance.h @@ -49,7 +49,7 @@ struct yottasiemens : prefixed_unit {}; struct dim_conductance : physical::dim_conductance {}; -template +template U, QuantityValue Rep = double> using conductance = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/current_density.h b/src/include/units/physical/si/derived/current_density.h index 1ca4065d..cf799931 100644 --- a/src/include/units/physical/si/derived/current_density.h +++ b/src/include/units/physical/si/derived/current_density.h @@ -34,7 +34,7 @@ struct ampere_per_metre_sq : unit {}; struct dim_current_density : physical::dim_current_density {}; -template +template U, QuantityValue Rep = double> using current_density = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/density.h b/src/include/units/physical/si/derived/density.h index 52b32275..e74d690d 100644 --- a/src/include/units/physical/si/derived/density.h +++ b/src/include/units/physical/si/derived/density.h @@ -34,7 +34,7 @@ struct kilogram_per_metre_cub : unit {}; struct dim_density : physical::dim_density {}; -template +template U, QuantityValue Rep = double> using density = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/dynamic_viscosity.h b/src/include/units/physical/si/derived/dynamic_viscosity.h index 8757770a..cb83d58d 100644 --- a/src/include/units/physical/si/derived/dynamic_viscosity.h +++ b/src/include/units/physical/si/derived/dynamic_viscosity.h @@ -32,7 +32,7 @@ namespace units::physical::si { struct pascal_second : unit {}; struct dim_dynamic_viscosity : physical::dim_dynamic_viscosity {}; -template +template U, QuantityValue Rep = double> using dynamic_viscosity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/electric_charge.h b/src/include/units/physical/si/derived/electric_charge.h index b0c1fee9..80608187 100644 --- a/src/include/units/physical/si/derived/electric_charge.h +++ b/src/include/units/physical/si/derived/electric_charge.h @@ -33,7 +33,7 @@ struct coulomb : named_unit {}; struct dim_electric_charge : physical::dim_electric_charge {}; -template +template U, QuantityValue Rep = double> using electric_charge = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/electric_field_strength.h b/src/include/units/physical/si/derived/electric_field_strength.h index d3af926f..dd657971 100644 --- a/src/include/units/physical/si/derived/electric_field_strength.h +++ b/src/include/units/physical/si/derived/electric_field_strength.h @@ -31,7 +31,7 @@ namespace units::physical::si { struct volt_per_metre : unit {}; struct dim_electric_field_strength : physical::dim_electric_field_strength {}; -template +template U, QuantityValue Rep = double> using electric_field_strength = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/energy.h b/src/include/units/physical/si/derived/energy.h index 9c2b231f..9de89aae 100644 --- a/src/include/units/physical/si/derived/energy.h +++ b/src/include/units/physical/si/derived/energy.h @@ -52,7 +52,7 @@ struct gigaelectronvolt : prefixed_unit {} struct dim_energy : physical::dim_energy {}; -template +template U, QuantityValue Rep = double> using energy = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/force.h b/src/include/units/physical/si/derived/force.h index cf1882c1..40aefb98 100644 --- a/src/include/units/physical/si/derived/force.h +++ b/src/include/units/physical/si/derived/force.h @@ -54,7 +54,7 @@ struct yottanewton : prefixed_unit {}; struct dim_force : physical::dim_force {}; -template +template U, QuantityValue Rep = double> using force = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/frequency.h b/src/include/units/physical/si/derived/frequency.h index c804f23d..89e03ba4 100644 --- a/src/include/units/physical/si/derived/frequency.h +++ b/src/include/units/physical/si/derived/frequency.h @@ -48,7 +48,7 @@ struct yottahertz : prefixed_unit {}; struct dim_frequency : physical::dim_frequency {}; -template +template U, QuantityValue Rep = double> using frequency = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/heat_capacity.h b/src/include/units/physical/si/derived/heat_capacity.h index e0fcc2c2..9d78bc8e 100644 --- a/src/include/units/physical/si/derived/heat_capacity.h +++ b/src/include/units/physical/si/derived/heat_capacity.h @@ -39,13 +39,13 @@ struct dim_heat_capacity : physical::dim_heat_capacity {}; struct dim_molar_heat_capacity : physical::dim_molar_heat_capacity {}; -template +template U, QuantityValue Rep = double> using heat_capacity = quantity; -template +template U, QuantityValue Rep = double> using specific_heat_capacity = quantity; -template +template U, QuantityValue Rep = double> using molar_heat_capacity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/inductance.h b/src/include/units/physical/si/derived/inductance.h index 397eb50d..f804c12a 100644 --- a/src/include/units/physical/si/derived/inductance.h +++ b/src/include/units/physical/si/derived/inductance.h @@ -50,7 +50,7 @@ struct yottahenry : prefixed_unit {}; struct dim_inductance : physical::dim_inductance {}; -template +template U, QuantityValue Rep = double> using inductance = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/luminance.h b/src/include/units/physical/si/derived/luminance.h index 1e7f060c..54c906bc 100644 --- a/src/include/units/physical/si/derived/luminance.h +++ b/src/include/units/physical/si/derived/luminance.h @@ -32,7 +32,7 @@ namespace units::physical::si { struct candela_per_metre_sq : unit {}; struct dim_luminance : physical::dim_luminance {}; -template +template U, QuantityValue Rep = double> using luminance = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/magnetic_flux.h b/src/include/units/physical/si/derived/magnetic_flux.h index 6f9927a4..eeb63ed4 100644 --- a/src/include/units/physical/si/derived/magnetic_flux.h +++ b/src/include/units/physical/si/derived/magnetic_flux.h @@ -50,7 +50,7 @@ struct yottaweber : prefixed_unit {}; struct dim_magnetic_flux : physical::dim_magnetic_flux {}; -template +template U, QuantityValue Rep = double> using magnetic_flux = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/magnetic_induction.h b/src/include/units/physical/si/derived/magnetic_induction.h index b048e3ee..d8109462 100644 --- a/src/include/units/physical/si/derived/magnetic_induction.h +++ b/src/include/units/physical/si/derived/magnetic_induction.h @@ -54,7 +54,7 @@ struct gauss : named_scaled_unit {} struct dim_magnetic_induction : physical::dim_magnetic_induction {}; -template +template U, QuantityValue Rep = double> using magnetic_induction = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/molar_energy.h b/src/include/units/physical/si/derived/molar_energy.h index 4dfc6f26..ccca1978 100644 --- a/src/include/units/physical/si/derived/molar_energy.h +++ b/src/include/units/physical/si/derived/molar_energy.h @@ -34,7 +34,7 @@ struct joule_per_mole : unit {}; struct dim_molar_energy : physical::dim_molar_energy {}; -template +template U, QuantityValue Rep = double> using molar_energy = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/momentum.h b/src/include/units/physical/si/derived/momentum.h index 5273d379..acce4b94 100644 --- a/src/include/units/physical/si/derived/momentum.h +++ b/src/include/units/physical/si/derived/momentum.h @@ -32,7 +32,7 @@ namespace units::physical::si { struct kilogram_metre_per_second : unit {}; struct dim_momentum : physical::dim_momentum {}; -template +template U, QuantityValue Rep = double> using momentum = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/permeability.h b/src/include/units/physical/si/derived/permeability.h index 88040be5..95e50642 100644 --- a/src/include/units/physical/si/derived/permeability.h +++ b/src/include/units/physical/si/derived/permeability.h @@ -33,7 +33,7 @@ struct henry_per_metre : unit {}; struct dim_permeability : physical::dim_permeability {}; -template +template U, QuantityValue Rep = double> using permeability = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/permittivity.h b/src/include/units/physical/si/derived/permittivity.h index 5aa4842a..37d09e39 100644 --- a/src/include/units/physical/si/derived/permittivity.h +++ b/src/include/units/physical/si/derived/permittivity.h @@ -33,7 +33,7 @@ struct farad_per_metre : unit {}; struct dim_permittivity : physical::dim_permittivity {}; -template +template U, QuantityValue Rep = double> using permittivity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/power.h b/src/include/units/physical/si/derived/power.h index 80345275..30fb0ac5 100644 --- a/src/include/units/physical/si/derived/power.h +++ b/src/include/units/physical/si/derived/power.h @@ -49,7 +49,7 @@ struct yottawatt : prefixed_unit {}; struct dim_power : physical::dim_power {}; -template +template U, QuantityValue Rep = double> using power = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/pressure.h b/src/include/units/physical/si/derived/pressure.h index ac33f941..01d15449 100644 --- a/src/include/units/physical/si/derived/pressure.h +++ b/src/include/units/physical/si/derived/pressure.h @@ -54,7 +54,7 @@ struct yottapascal : prefixed_unit {}; struct dim_pressure : physical::dim_pressure {}; -template +template U, QuantityValue Rep = double> using pressure = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/resistance.h b/src/include/units/physical/si/derived/resistance.h index b7b4c199..be26345d 100644 --- a/src/include/units/physical/si/derived/resistance.h +++ b/src/include/units/physical/si/derived/resistance.h @@ -50,7 +50,7 @@ struct yottaohm : prefixed_unit {}; struct dim_resistance : physical::dim_resistance {}; -template +template U, QuantityValue Rep = double> using resistance = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/speed.h b/src/include/units/physical/si/derived/speed.h index 8313f80a..4bb44a41 100644 --- a/src/include/units/physical/si/derived/speed.h +++ b/src/include/units/physical/si/derived/speed.h @@ -34,7 +34,7 @@ struct dim_speed : physical::dim_speed {}; -template +template U, QuantityValue Rep = double> using speed = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/surface_tension.h b/src/include/units/physical/si/derived/surface_tension.h index 7f38a400..30f37c64 100644 --- a/src/include/units/physical/si/derived/surface_tension.h +++ b/src/include/units/physical/si/derived/surface_tension.h @@ -32,7 +32,7 @@ struct newton_per_metre : unit {}; struct dim_surface_tension : physical::dim_surface_tension {}; -template +template U, QuantityValue Rep = double> using surface_tension = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/thermal_conductivity.h b/src/include/units/physical/si/derived/thermal_conductivity.h index 56bbfea7..cb5eb6e6 100644 --- a/src/include/units/physical/si/derived/thermal_conductivity.h +++ b/src/include/units/physical/si/derived/thermal_conductivity.h @@ -33,7 +33,7 @@ struct watt_per_metre_kelvin : unit {}; struct dim_thermal_conductivity : physical::dim_thermal_conductivity {}; -template +template U, QuantityValue Rep = double> using thermal_conductivity = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/torque.h b/src/include/units/physical/si/derived/torque.h index cfeb4f9f..932a21eb 100644 --- a/src/include/units/physical/si/derived/torque.h +++ b/src/include/units/physical/si/derived/torque.h @@ -34,7 +34,7 @@ struct newton_metre : named_unit {}; struct dim_torque : physical::dim_torque> {}; -template +template U, QuantityValue Rep = double> using torque = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/voltage.h b/src/include/units/physical/si/derived/voltage.h index 0b88343f..77b4a7cf 100644 --- a/src/include/units/physical/si/derived/voltage.h +++ b/src/include/units/physical/si/derived/voltage.h @@ -54,7 +54,7 @@ struct yottavolt : prefixed_unit {}; struct dim_voltage : physical::dim_voltage {}; -template +template U, QuantityValue Rep = double> using voltage = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/derived/volume.h b/src/include/units/physical/si/derived/volume.h index 24005c9f..e81b760f 100644 --- a/src/include/units/physical/si/derived/volume.h +++ b/src/include/units/physical/si/derived/volume.h @@ -74,7 +74,7 @@ struct exalitre : prefixed_unit {}; struct zettalitre : prefixed_alias_unit {}; struct yottalitre : prefixed_unit {}; -template +template U, QuantityValue Rep = double> using volume = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/base/length.h b/src/include/units/physical/si/fps/base/length.h index 8d2255ef..1424347a 100644 --- a/src/include/units/physical/si/fps/base/length.h +++ b/src/include/units/physical/si/fps/base/length.h @@ -51,7 +51,7 @@ struct nautical_mile : named_scaled_unit {}; -template +template U, QuantityValue Rep = double> using length = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/base/mass.h b/src/include/units/physical/si/fps/base/mass.h index a79f94fb..da264dbd 100644 --- a/src/include/units/physical/si/fps/base/mass.h +++ b/src/include/units/physical/si/fps/base/mass.h @@ -32,7 +32,7 @@ struct pound : named_scaled_unit {}; -template +template U, QuantityValue Rep = double> using mass = quantity; struct grain : named_scaled_unit{}; diff --git a/src/include/units/physical/si/fps/derived/acceleration.h b/src/include/units/physical/si/fps/derived/acceleration.h index 67ec4609..c5e7e27b 100644 --- a/src/include/units/physical/si/fps/derived/acceleration.h +++ b/src/include/units/physical/si/fps/derived/acceleration.h @@ -31,7 +31,7 @@ namespace units::physical::si::fps { struct foot_per_second_sq : unit {}; struct dim_acceleration : physical::dim_acceleration {}; -template +template U, QuantityValue Rep = double> using acceleration = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/derived/area.h b/src/include/units/physical/si/fps/derived/area.h index 11fd430d..38252892 100644 --- a/src/include/units/physical/si/fps/derived/area.h +++ b/src/include/units/physical/si/fps/derived/area.h @@ -32,7 +32,7 @@ struct square_foot : unit {}; struct dim_area : physical::dim_area {}; -template +template U, QuantityValue Rep = double> using area = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/derived/density.h b/src/include/units/physical/si/fps/derived/density.h index 9ebaf613..f8791d24 100644 --- a/src/include/units/physical/si/fps/derived/density.h +++ b/src/include/units/physical/si/fps/derived/density.h @@ -33,7 +33,7 @@ struct pound_per_foot_cub : unit {}; struct dim_density : physical::dim_density {}; -template +template U, QuantityValue Rep = double> using density = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/derived/energy.h b/src/include/units/physical/si/fps/derived/energy.h index 55669164..03b8fc66 100644 --- a/src/include/units/physical/si/fps/derived/energy.h +++ b/src/include/units/physical/si/fps/derived/energy.h @@ -39,7 +39,7 @@ struct foot_pound_force : noble_deduced_unit +template U, QuantityValue Rep = double> using energy = quantity; diff --git a/src/include/units/physical/si/fps/derived/force.h b/src/include/units/physical/si/fps/derived/force.h index 4e2008b2..592a2e93 100644 --- a/src/include/units/physical/si/fps/derived/force.h +++ b/src/include/units/physical/si/fps/derived/force.h @@ -43,7 +43,7 @@ struct kip : alias_unit {}; struct dim_force : physical::dim_force {}; -template +template U, QuantityValue Rep = double> using force = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/derived/power.h b/src/include/units/physical/si/fps/derived/power.h index 2bad905e..716f2a2c 100644 --- a/src/include/units/physical/si/fps/derived/power.h +++ b/src/include/units/physical/si/fps/derived/power.h @@ -37,7 +37,7 @@ struct foot_pound_force_per_second : deduced_unit {}; -template +template U, QuantityValue Rep = double> using power = quantity; inline namespace literals { diff --git a/src/include/units/physical/si/fps/derived/pressure.h b/src/include/units/physical/si/fps/derived/pressure.h index 53016007..f7820300 100644 --- a/src/include/units/physical/si/fps/derived/pressure.h +++ b/src/include/units/physical/si/fps/derived/pressure.h @@ -34,7 +34,7 @@ struct poundal_per_foot_sq : unit {}; struct dim_pressure : physical::dim_pressure {}; -template +template U, QuantityValue Rep = double> using pressure = quantity; struct pound_force_per_foot_sq : named_scaled_unit {}; diff --git a/src/include/units/physical/si/fps/derived/speed.h b/src/include/units/physical/si/fps/derived/speed.h index 982b18aa..74ccf82e 100644 --- a/src/include/units/physical/si/fps/derived/speed.h +++ b/src/include/units/physical/si/fps/derived/speed.h @@ -32,7 +32,7 @@ namespace units::physical::si::fps { struct foot_per_second : unit {}; struct dim_speed : physical::dim_speed {}; -template +template U, QuantityValue Rep = double> using speed = quantity; struct mile_per_hour : deduced_unit{}; diff --git a/src/include/units/physical/si/fps/derived/volume.h b/src/include/units/physical/si/fps/derived/volume.h index 3cf4c29c..4e834b0c 100644 --- a/src/include/units/physical/si/fps/derived/volume.h +++ b/src/include/units/physical/si/fps/derived/volume.h @@ -33,7 +33,7 @@ struct dim_volume : physical::dim_volume {}; struct cubic_yard : deduced_unit {}; -template +template U, QuantityValue Rep = double> using volume = quantity; inline namespace literals { diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index d2312737..2787ab8d 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -34,19 +34,52 @@ namespace units { -namespace detail { +template +concept floating_point_ = // exposition only + (Quantity && treat_as_floating_point) || + (!Quantity && treat_as_floating_point); template -concept safe_convertible = // exposition only +concept safe_convertible_to_ = // exposition only + !(Quantity) && + !(Quantity) && std::convertible_to && - (treat_as_floating_point || (!treat_as_floating_point)); + (floating_point_ || (!floating_point_)); -template -concept safe_divisible = // exposition only - treat_as_floating_point || - is_integral(quantity_ratio(QuantityFrom{}) / quantity_ratio(QuantityTo{})); +// QFrom ratio is an exact multiple of QTo +template +concept harmonic_ = // exposition only + Quantity && + Quantity && + requires(QFrom from, QTo to) { requires is_integral(detail::quantity_ratio(from) / detail::quantity_ratio(to)); }; -} // namespace detail +template +concept safe_castable_to_ = // exposition only + Quantity && + QuantityOf && + scalable_with_ && + (floating_point_ || (!floating_point_ && harmonic_)); + +template +concept quantity_value_for_ = + std::regular_invocable && + QuantityValue>; + +template +concept invoke_result_convertible_to_ = + QuantityValue && + quantity_value_for_ && + safe_convertible_to_>; + +template +concept have_quantity_for_ = + Quantity && + (!Quantity) && + quantity_value_for_; + +template Q2> + requires quantity_value_for_ +using common_quantity_for = common_quantity>; /** * @brief A quantity @@ -58,63 +91,69 @@ concept safe_divisible = // exposition only * @tparam U a measurement unit of the quantity * @tparam Rep a type to be used to represent values of a quantity */ -template U, ScalableNumber Rep = double> +template U, QuantityValue Rep = double> class quantity { Rep value_; public: + // member types using dimension = D; using unit = U; using rep = Rep; + // static member functions + [[nodiscard]] static constexpr quantity zero() noexcept + requires requires { quantity_values::zero(); } + { + return quantity(quantity_values::zero()); + } + + [[nodiscard]] static constexpr quantity one() noexcept + requires requires { quantity_values::one(); } + { + return quantity(quantity_values::one()); + } + + [[nodiscard]] static constexpr quantity min() noexcept + requires requires { quantity_values::min(); } + { + return quantity(quantity_values::min()); + } + + [[nodiscard]] static constexpr quantity max() noexcept + requires requires { quantity_values::max(); } + { + return quantity(quantity_values::max()); + } + + // construction, assignment, destruction quantity() = default; quantity(const quantity&) = default; quantity(quantity&&) = default; - template - requires detail::safe_convertible - constexpr explicit(!(equivalent>)) quantity(const Value& v) : value_{static_cast(v)} {} + template Value> + explicit(!(equivalent>)) constexpr quantity(const Value& v) : value_(static_cast(v)) {} - template - requires equivalent && - detail::safe_convertible && - detail::safe_divisible - constexpr quantity(const Q2& q) : value_{quantity_cast(q).count()} {} + template Q2> + constexpr quantity(const Q2& q) : value_(quantity_cast(q).count()) {} quantity& operator=(const quantity&) = default; quantity& operator=(quantity&&) = default; + // data access [[nodiscard]] constexpr rep count() const noexcept { return value_; } - [[nodiscard]] static constexpr quantity zero() noexcept - requires requires { quantity_values::zero(); } + // member unary operators + [[nodiscard]] constexpr quantity operator+() const + requires requires(rep v) { { +v } -> std::same_as; } { - return quantity(quantity_values::zero()); + return *this; } - [[nodiscard]] static constexpr quantity one() noexcept - requires requires { quantity_values::one(); } - { - return quantity(quantity_values::one()); - } - - [[nodiscard]] static constexpr quantity min() noexcept - requires requires { quantity_values::min(); } - { - return quantity(quantity_values::min()); - } - - [[nodiscard]] static constexpr quantity max() noexcept - requires requires { quantity_values::max(); } - { - return quantity(quantity_values::max()); - } - - [[nodiscard]] constexpr quantity operator+() const { return *this; } - - [[nodiscard]] constexpr quantity operator-() const + [[nodiscard]] constexpr Quantity auto operator-() const requires std::regular_invocable, rep> { - return quantity(-count()); + using ret = quantity; + return ret(-count()); } constexpr quantity& operator++() @@ -143,51 +182,45 @@ public: return quantity(value_--); } - template - requires detail::safe_convertible - constexpr quantity& operator+=(const quantity& q) + constexpr quantity& operator+=(const quantity& q) + requires requires(rep a, rep b) { { a += b } -> std::same_as; } { value_ += q.count(); return *this; } - template - requires detail::safe_convertible - constexpr quantity& operator-=(const quantity& q) + constexpr quantity& operator-=(const quantity& q) + requires requires(rep a, rep b) { { a -= b } -> std::same_as; } { value_ -= q.count(); return *this; } - template - requires detail::safe_convertible - constexpr quantity& operator*=(const Rep2& rhs) + constexpr quantity& operator*=(const rep& rhs) + requires requires(rep a, rep b) { { a *= b } -> std::same_as; } { value_ *= rhs; return *this; } - template - requires detail::safe_convertible - constexpr quantity& operator/=(const Rep2& rhs) + constexpr quantity& operator/=(const rep& rhs) + requires requires(rep a, rep b) { { a /= b } -> std::same_as; } { value_ /= rhs; return *this; } - template - requires (!treat_as_floating_point) && - (!treat_as_floating_point) - constexpr quantity& operator%=(const Value& rhs) - requires requires(rep v1, Value v2) { { v1 %= v2 } -> std::same_as; } + constexpr quantity& operator%=(const rep& rhs) + requires (!floating_point_) && + requires(rep a, rep b) { { a %= b } -> std::same_as; } { value_ %= rhs; return *this; } constexpr quantity& operator%=(const quantity& q) - requires (!treat_as_floating_point) && - requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as; } + requires (!floating_point_) && + requires(rep a, rep b) { { a %= b } -> std::same_as; } { value_ %= q.count(); return *this; @@ -195,143 +228,88 @@ public: // Hidden Friends // Below friend functions are to be found via argument-dependent lookup only - [[nodiscard]] friend constexpr quantity operator+(const quantity& lhs, const quantity& rhs) - requires std::regular_invocable, Rep, Rep> + requires invoke_result_convertible_to_, rep, rep> { return quantity(lhs.count() + rhs.count()); } - template - requires std::regular_invocable, Rep, Rep2> && equivalent - [[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) - { - using common_rep = decltype(lhs.count() + rhs.count()); - using ret = common_quantity, common_rep>; - return ret(ret(lhs).count() + ret(rhs).count()); - } - [[nodiscard]] friend constexpr quantity operator-(const quantity& lhs, const quantity& rhs) - requires std::regular_invocable, Rep, Rep> + requires invoke_result_convertible_to_, rep, rep> { return quantity(lhs.count() - rhs.count()); } - template - requires std::regular_invocable, Rep, Rep2> && equivalent - [[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) - { - using common_rep = decltype(lhs.count() - rhs.count()); - using ret = common_quantity, common_rep>; - return ret(ret(lhs).count() - ret(rhs).count()); - } - - template - requires std::regular_invocable, Rep, Value> + template + requires (!Quantity) && + invoke_result_convertible_to_, rep, Value> [[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v) { - using common_rep = decltype(q.count() * v); - using ret = quantity; + using ret = quantity, rep, Value>>; return ret(q.count() * v); } - template - requires std::regular_invocable, Value, Rep> + template + requires (!Quantity) && + invoke_result_convertible_to_, rep, Value> [[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q) { return q * v; } - template - requires std::regular_invocable, Rep, Rep2> - [[nodiscard]] friend constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) - { - using dim = dimension_multiply; - using ret_unit = downcast_unit::ratio) * (U2::ratio / dimension_unit::ratio) * dimension_unit::ratio>; - using common_rep = decltype(lhs.count() * rhs.count()); - using ret = quantity; - return ret(lhs.count() * rhs.count()); - } - - template - requires std::regular_invocable, Value, Rep> - [[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q) - { - // Expects(q.count() != zero().count()); - - using dim = dim_invert; - using ret_unit = downcast_unit; - using common_rep = decltype(v / q.count()); - using ret = quantity; - return ret(v / q.count()); - } - - template - requires std::regular_invocable, Rep, Value> + template + requires (!Quantity) && + invoke_result_convertible_to_, rep, Value> [[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v) { // Expects(v != zero().count()); - - using common_rep = decltype(q.count() / v); - using ret = quantity; + using ret = quantity, rep, Value>>; return ret(q.count() / v); } - template - requires std::regular_invocable, Rep, Rep2> - [[nodiscard]] friend constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) + template + requires (!Quantity) && + invoke_result_convertible_to_, Value, rep> + [[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q) { - // Expects(rhs.count() != zero().count()); - - using common_rep = decltype(lhs.count() / rhs.count()); - using dim = dimension_divide; - using ret_unit = downcast_unit::ratio) / (U2::ratio / dimension_unit::ratio) * dimension_unit::ratio>; - using ret = quantity; - return ret(lhs.count() / rhs.count()); + // Expects(q.count() != zero().count()); + using dim = dim_invert; + using ret_unit = downcast_unit; + using ret = quantity, Value, rep>>; + return ret(v / q.count()); } - template - requires (!treat_as_floating_point) && - (!treat_as_floating_point) && - std::regular_invocable, Rep, Value> + template + requires (!Quantity) && (!floating_point_) && (!floating_point_) && + invoke_result_convertible_to_, rep, Value> [[nodiscard]] friend constexpr Quantity auto operator%(const quantity& q, const Value& v) { - using common_rep = decltype(q.count() % v); - using ret = quantity; + using ret = quantity, rep, Value>>; return ret(q.count() % v); } - template - requires (!treat_as_floating_point) && - (!treat_as_floating_point) && - std::regular_invocable, Rep, Rep2> - [[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr quantity operator%(const quantity& lhs, const quantity& rhs) + requires (!floating_point_) && + invoke_result_convertible_to_, rep, rep> { - using common_rep = decltype(lhs.count() % rhs.count()); - using ret = common_quantity, common_rep>; - return ret(ret(lhs).count() % ret(rhs).count()); + return quantity(lhs.count() % rhs.count()); } - template - requires equivalent && - std::three_way_comparable_with - [[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) + requires std::three_way_comparable +#if COMP_GCC == 10 && COMP_GCC_MINOR >= 2 + = default; +#else { - using cq = common_quantity>; - return cq(lhs).count() <=> cq(rhs).count(); + return lhs.count() <=> rhs.count(); } +#endif - template - requires equivalent && - std::equality_comparable_with - [[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity& rhs) - { - using cq = common_quantity>; - return cq(lhs).count() == cq(rhs).count(); - } + [[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity& rhs) = default; template friend std::basic_ostream& operator<<(std::basic_ostream& os, const quantity& q) + requires requires { os << q.count(); } { if(os.width()) { // std::setw() applies to the whole quantity output so it has to be first put into std::string @@ -345,9 +323,82 @@ public: } }; -template +// CTAD +template /* implicit */ quantity(V) -> quantity; +template Q2> + requires quantity_value_for_, typename Q1::rep, typename Q2::rep> +[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs) +{ + using ret = common_quantity_for, Q1, Q2>; + return ret(ret(lhs).count() + ret(rhs).count()); +} + +template Q2> + requires quantity_value_for_, typename Q1::rep, typename Q2::rep> +[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs) +{ + using ret = common_quantity_for, Q1, Q2>; + return ret(ret(lhs).count() - ret(rhs).count()); +} + +template + requires quantity_value_for_, Rep1, Rep2> +[[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) +{ + using dim = dimension_multiply; + using unit = downcast_unit::ratio) * (U2::ratio / dimension_unit::ratio) * dimension_unit::ratio>; + using ret = quantity, Rep1, Rep2>>; + return ret(lhs.count() * rhs.count()); +} + +template + requires quantity_value_for_, Rep1, Rep2> +[[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) +{ + // Expects(rhs.count() != zero().count()); + using dim = dimension_divide; + using unit = downcast_unit::ratio) / (U2::ratio / dimension_unit::ratio) * dimension_unit::ratio>; + using ret = quantity, Rep1, Rep2>>; + return ret(lhs.count() / rhs.count()); +} + +template + requires (!floating_point_) && (!floating_point_) && + quantity_value_for_, Rep1, Rep2> +[[nodiscard]] constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs) +{ + using unit = downcast_unit; + using ret = quantity, Rep1, Rep2>>; + return ret(lhs.count() % rhs.count()); +} + +template Q2> + requires (!floating_point_) && (!floating_point_) && + quantity_value_for_, typename Q1::rep, typename Q2::rep> +[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs) +{ + using ret = common_quantity_for, Q1, Q2>; + return ret(ret(lhs).count() % ret(rhs).count()); +} + +template Q2> + requires std::three_way_comparable_with +[[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs) +{ + using cq = common_quantity; + return cq(lhs).count() <=> cq(rhs).count(); +} + +template Q2> + requires std::equality_comparable_with +[[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs) +{ + using cq = common_quantity; + return cq(lhs).count() == cq(rhs).count(); +} + namespace detail { template diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index fab7f6d4..2d9bacc6 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -36,10 +36,10 @@ namespace units { -template U, ScalableNumber Rep> +template U, QuantityValue Rep> class quantity; -template U, ScalableNumber Rep> +template U, QuantityValue Rep> class quantity_point; namespace detail { @@ -55,232 +55,6 @@ constexpr auto quantity_ratio(const quantity&) } } -} // namespace detail - -// quantity_cast -namespace detail { - -template -struct quantity_cast_impl; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(q.count())); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * static_cast(detail::fpow10(CRatio.exp)))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * static_cast(detail::ipow10(CRatio.exp)))); - } - else { - return To(static_cast(static_cast(q.count()) / static_cast(detail::ipow10(-CRatio.exp)))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(static_cast(q.count()) * - (static_cast(CRatio.num) / - static_cast(CRatio.den)))); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * - (static_cast(detail::fpow10(CRatio.exp)) * - (static_cast(CRatio.num) / - static_cast(CRatio.den))))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * - (static_cast(CRatio.num) * - static_cast(detail::ipow10(CRatio.exp)) / - static_cast(CRatio.den)))); - } - else { - return To(static_cast(static_cast(q.count()) * - (static_cast(CRatio.num) / - (static_cast(CRatio.den) * - static_cast(detail::ipow10(-CRatio.exp)))))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(static_cast(q.count()) / static_cast(CRatio.den))); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * (static_cast(detail::fpow10(CRatio.exp)) * (CRep{1} / static_cast(CRatio.den))))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * (static_cast(detail::ipow10(CRatio.exp)) / static_cast(CRatio.den)))); - } - else { - return To(static_cast(static_cast(q.count()) / (static_cast(detail::ipow10(-CRatio.exp)) * static_cast(CRatio.den)))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num))); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * (static_cast(CRatio.num) * static_cast(detail::fpow10(CRatio.exp))))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * (static_cast(CRatio.num) * static_cast(detail::ipow10(CRatio.exp))))); - } - else { - return To(static_cast(static_cast(q.count()) * (static_cast(CRatio.num) / static_cast(detail::ipow10(-CRatio.exp))))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * detail::fpow10(CRatio.exp))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * detail::ipow10(CRatio.exp))); - } - else { - return To(static_cast(q.count() / detail::ipow10(-CRatio.exp))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(q.count() * (CRatio.num / CRatio.den))); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * (detail::fpow10(CRatio.exp) * (CRatio.num / CRatio.den)))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * (CRatio.num * detail::ipow10(CRatio.exp) / CRatio.den))); - } - else { - return To(static_cast(q.count()) * (CRatio.num / (CRatio.den * detail::ipow10(-CRatio.exp)))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(q.count() / CRatio.den)); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * (detail::fpow10(CRatio.exp) / CRatio.den))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * (detail::ipow10(CRatio.exp) / CRatio.den))); - } - else { - return To(static_cast(q.count() / (detail::ipow10(-CRatio.exp) * CRatio.den))); - } - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(q.count() * CRatio.num)); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * (CRatio.num * detail::fpow10(CRatio.exp)))); - } else { - if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * (CRatio.num * detail::ipow10(CRatio.exp)))); - } - else { - return To(static_cast(q.count() * (CRatio.num / detail::ipow10(-CRatio.exp)))); - } - } - } -}; - template constexpr ratio cast_ratio(const Q1& from, const Q2& to) { @@ -294,6 +68,26 @@ constexpr ratio cast_ratio(const Q1& from, const Q2& to) } } +template +struct cast_traits; + +template + requires common_type_with_, std::intmax_t> +struct cast_traits { + using ratio_type = std::common_type_t, std::intmax_t>; + using rep_type = ratio_type; +}; + +template + requires (!common_type_with_, std::intmax_t>) && + scalable_number_, std::intmax_t> && + requires { typename std::common_type_t::value_type; } && + common_type_with_::value_type, std::intmax_t> +struct cast_traits { + using ratio_type = std::common_type_t::value_type, std::intmax_t>; + using rep_type = std::common_type_t; +}; + } // namespace detail /** @@ -308,16 +102,33 @@ constexpr ratio cast_ratio(const Q1& from, const Q2& to) * * @tparam To a target quantity type to cast to */ -template +template Rep> requires QuantityOf [[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - using c_ratio = std::integral_constant(), To())>; - using c_rep = std::common_type_t; using ret_unit = downcast_unit; using ret = quantity; - using cast = detail::quantity_cast_impl; - return cast::cast(q); + using traits = detail::cast_traits; + using ratio_type = TYPENAME traits::ratio_type; + using rep_type = TYPENAME traits::rep_type; + constexpr auto c_ratio = detail::cast_ratio(quantity(), To()); + + if constexpr (treat_as_floating_point) { + return ret(static_cast(static_cast(q.count()) * + (static_cast(c_ratio.num) * detail::fpow10(c_ratio.exp) / static_cast(c_ratio.den)))); + } + else { + if constexpr (c_ratio.exp > 0) { + return ret(static_cast(static_cast(q.count()) * + (static_cast(c_ratio.num) * static_cast(detail::ipow10(c_ratio.exp))) / + static_cast(c_ratio.den))); + } + else { + return ret(static_cast(static_cast(q.count()) * + static_cast(c_ratio.num) / + (static_cast(c_ratio.den) * static_cast(detail::ipow10(-c_ratio.exp))))); + } + } } /** @@ -393,7 +204,7 @@ template * * @tparam ToRep a representation type to use for a target quantity */ -template +template Rep> [[nodiscard]] constexpr auto quantity_cast(const quantity& q) { return quantity_cast>(q); diff --git a/src/include/units/quantity_point.h b/src/include/units/quantity_point.h index 5de4ba09..cecdc716 100644 --- a/src/include/units/quantity_point.h +++ b/src/include/units/quantity_point.h @@ -37,7 +37,7 @@ namespace units { * @tparam U a measurement unit of the quantity point * @tparam Rep a type to be used to represent values of a quantity point */ -template U, ScalableNumber Rep = double> +template U, QuantityValue Rep = double> class quantity_point { public: using quantity_type = quantity; diff --git a/test/unit_test/static/CMakeLists.txt b/test/unit_test/static/CMakeLists.txt index afe82e06..f9f245e4 100644 --- a/test/unit_test/static/CMakeLists.txt +++ b/test/unit_test/static/CMakeLists.txt @@ -24,7 +24,9 @@ cmake_minimum_required(VERSION 3.12) add_library(unit_tests_static cgs_test.cpp - custom_rep_min_req_test.cpp + concepts_test.cpp + custom_rep_test_min_expl.cpp + custom_rep_test_min_impl.cpp custom_unit_test.cpp data_test.cpp dimension_op_test.cpp diff --git a/test/unit_test/static/concepts_test.cpp b/test/unit_test/static/concepts_test.cpp new file mode 100644 index 00000000..fe4986e6 --- /dev/null +++ b/test/unit_test/static/concepts_test.cpp @@ -0,0 +1,130 @@ +// 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 "units/physical/si/cgs/derived/speed.h" +#include "units/physical/si/derived/speed.h" +#include "units/physical/si/fps/derived/speed.h" +#include "units/quantity_point.h" +#include +#include +#include +#include +#include + +namespace { + +using namespace units; +using namespace units::physical; + +// Prefix family + +static_assert(PrefixFamily); +static_assert(!PrefixFamily); + +// Prefix + +static_assert(Prefix); +static_assert(!Prefix); +static_assert(!Prefix); + +// UnitRatio + +static_assert(UnitRatio); +static_assert(!UnitRatio); +// static_assert(UnitRatio); // static_assert in ratio +static_assert(UnitRatio); +static_assert(!UnitRatio); +static_assert(!UnitRatio); + +// BaseDimension + +static_assert(BaseDimension); +static_assert(!BaseDimension); +static_assert(!BaseDimension); + +// DerivedDimension + +static_assert(DerivedDimension); +static_assert(!DerivedDimension); +static_assert(!DerivedDimension); + +// Dimension + +static_assert(Dimension); +static_assert(Dimension); +static_assert(!Dimension); +static_assert(!Dimension); +static_assert(!Dimension); + +// Unit + +static_assert(Unit); +static_assert(Unit); +static_assert(Unit); +static_assert(Unit); +static_assert(!Unit); +static_assert(!Unit); +static_assert(!Unit); + +// UnitOf + +static_assert(UnitOf); +static_assert(UnitOf); +static_assert(UnitOf); +static_assert(!UnitOf); + +// QuantityValue + +static_assert(QuantityValue); +static_assert(QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>>); +static_assert(!QuantityValue); +static_assert(!QuantityValue); + +// Quantity + +static_assert(Quantity>); +static_assert(!Quantity); +static_assert(!Quantity>); + +// QuantityPoint + +static_assert(QuantityPoint>); +static_assert(!QuantityPoint>); +static_assert(!QuantityPoint); + +// WrappedQuantity + +static_assert(wrapped_quantity_>>); +static_assert(!wrapped_quantity_, si::length>>); + +// QuantityOf + +static_assert(QuantityOf, si::dim_length>); +// TODO it seems `QuantityOf` is a bad name if `si::cgs::length` matches `si::fps::dim_length` +static_assert(QuantityOf, si::dim_length>); +static_assert(QuantityOf, si::dim_length>); +static_assert(QuantityOf, si::fps::dim_length>); +static_assert(!QuantityOf, si::dim_time>); + +} // namespace diff --git a/test/unit_test/static/custom_rep_min_req_test.cpp b/test/unit_test/static/custom_rep_min_req_test.cpp deleted file mode 100644 index 5db6f01a..00000000 --- a/test/unit_test/static/custom_rep_min_req_test.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// 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 "units/math.h" -#include "units/physical/si/si.h" -#include -#include -#include - -using namespace units; - -namespace { - -template -struct equality_ops { - [[nodiscard]] friend constexpr bool operator==(T lhs, T rhs) { return lhs.value_ == rhs.value_; } - [[nodiscard]] friend constexpr bool operator!=(T lhs, T rhs) { return !(lhs == rhs); } -}; - -template -struct scaling_ops { - [[nodiscard]] friend constexpr T operator*(T lhs, T rhs) { - return T(lhs.value_ * rhs.value_); - } - [[nodiscard]] friend constexpr T operator/(T lhs, T rhs) { - return T(lhs.value_ / rhs.value_); - } -}; - -template -struct scalar_ops : equality_ops, scaling_ops {}; - -template -struct impl_constructible : scalar_ops> { - T value_{}; - impl_constructible() = default; - constexpr impl_constructible(T v) : value_(std::move(v)) {} - // no conversion to fundamental arithmetic types -}; - -template -using impl = impl_constructible; - -template -struct expl_constructible : scalar_ops> { - T value_{}; - expl_constructible() = default; - constexpr explicit expl_constructible(T v) : value_(std::move(v)) {} - // no conversion to fundamental arithmetic types -}; - -template -using expl = expl_constructible; - -template -struct impl_constructible_impl_convertible : scalar_ops> /*, int_scaling_ops> */ { - T value_{}; - impl_constructible_impl_convertible() = default; - constexpr impl_constructible_impl_convertible(T v) : value_(std::move(v)) {} - constexpr operator const T&() const& { return value_; } -}; - -template -using impl_impl = impl_constructible_impl_convertible; - -static_assert(std::convertible_to>); -static_assert(std::convertible_to, float>); -static_assert(units::ScalableNumber>); - -template -struct expl_constructible_impl_convertible : scalar_ops> { - T value_{}; - expl_constructible_impl_convertible() = default; - constexpr explicit expl_constructible_impl_convertible(T v) : value_(std::move(v)) {} - constexpr operator const T&() const& { return value_; } -}; - -template -using expl_impl = expl_constructible_impl_convertible; - -static_assert(!std::convertible_to>); -static_assert(std::convertible_to, float>); -static_assert(units::ScalableNumber>); - -template -struct impl_constructible_expl_convertible : scalar_ops> { - T value_{}; - impl_constructible_expl_convertible() = default; - constexpr impl_constructible_expl_convertible(T v) : value_(std::move(v)) {} - constexpr explicit operator const T&() const& { return value_; } -}; - -template -using impl_expl = impl_constructible_expl_convertible; - -static_assert(std::convertible_to>); -static_assert(!std::convertible_to, float>); -static_assert(units::ScalableNumber>); - -template -struct expl_constructible_expl_convertible : scalar_ops> { - T value_{}; - expl_constructible_expl_convertible() = default; - constexpr explicit expl_constructible_expl_convertible(T v) : value_(std::move(v)) {} - constexpr explicit operator const T&() const& { return value_; } -}; - -template -using expl_expl = expl_constructible_expl_convertible; - -static_assert(!std::convertible_to>); -static_assert(!std::convertible_to, float>); -static_assert(units::ScalableNumber>); - -} // namespace - -namespace units { - -template -inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - -template -inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - -template -inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - -template -inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - -template -inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - -template -inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - -template -struct quantity_values> { - static constexpr impl zero() { return 0; } - static constexpr impl max() { return std::numeric_limits::max(); } - static constexpr impl min() { return std::numeric_limits::lowest(); } -}; - -} // namespace units - -namespace { - -using namespace units::physical::si; - -// constructors - -// Quantity from ScalableNumber -// int <- int -static_assert(length(expl_impl(1)).count() == 1); -static_assert(!std::is_constructible_v, impl_expl>); -static_assert(length(int(impl_expl(1))).count() == 1); -static_assert(!std::is_constructible_v>, int>); -static_assert(length>(expl_impl(1)).count() == expl_impl{1}); -static_assert(length>(1).count() == impl_expl{1}); - -// double <- double -static_assert(length(expl_impl(1.0)).count() == 1.0); -static_assert(!std::is_constructible_v, impl_expl>); -static_assert(length(double(impl_expl(1.0))).count() == 1.0); -static_assert(!std::is_constructible_v>, double>); -static_assert(length>(expl_impl(1.0)).count() == expl_impl{1.0}); -static_assert(length>(1.0).count() == impl_expl{1.0}); - -// double <- int -static_assert(length(expl_impl(1)).count() == 1.0); -static_assert(!std::is_constructible_v, impl_expl>); -static_assert(length(int(impl_expl(1))).count() == 1.0); -static_assert(!std::is_constructible_v>, int>); -static_assert(length>(expl_impl(1)).count() == expl_impl{1}); -static_assert(length>(1).count() == impl_expl{1.0}); - -// int <- double -static_assert(!std::is_constructible_v, expl_impl>); -static_assert(!std::is_constructible_v>, double>); - -// Quantity from other Quantity with different Rep -// int <- int -static_assert(length(length>(expl_impl(1))).count() == 1); -static_assert(!std::is_constructible_v, length>>); -static_assert(length(quantity_cast(length>(1))).count() == 1); -static_assert(!std::is_constructible_v>, length>); -static_assert(length>(quantity_cast>(length(1))).count() == expl_impl{1}); -static_assert(length>(length(1)).count() == impl_expl{1}); - -// double <- double -static_assert(length(length>(expl_impl(1.0))).count() == 1.0); -static_assert(!std::is_constructible_v, length>>); -static_assert(length(quantity_cast(length>(1.0))).count() == 1.0); -static_assert(!std::is_constructible_v>, length>); -static_assert(length>(quantity_cast>(length(1.0))).count() == expl_impl{1.0}); -static_assert(length>(length(1.0)).count() == impl_expl{1.0}); - -// double <- int -static_assert(length(length>(expl_impl(1))).count() == 1.0); -static_assert(!std::is_constructible_v, length>>); -static_assert(length(quantity_cast(length>(1))).count() == 1.0); -static_assert(!std::is_constructible_v>, length>); -static_assert(length>(quantity_cast>(length(1))).count() == expl_impl{1}); -static_assert(length>(length(1)).count() == impl_expl{1.0}); - -// int <- double -static_assert(!std::is_constructible_v, length>>); -static_assert(!std::is_constructible_v>, length>); - -// unit conversions - -static_assert(length>(length>(1)).count() == impl(1000)); -static_assert(length>(length>(expl(1))).count() == expl(1000)); -static_assert(length>(length>(1)).count() == impl_impl(1000)); -static_assert(length>(length>(1)).count() == impl_expl(1000)); -static_assert(length>(length>(expl_impl(1))).count() == expl_impl(1000)); -static_assert(length>(length>(expl_expl(1))).count() == expl_expl(1000)); - -static_assert(!std::is_constructible_v>, length>>); -static_assert(length>(quantity_cast(length>(2000))).count() == impl(2)); -static_assert(!std::is_constructible_v>, length>>); -static_assert(length>(quantity_cast(length>(expl(2000)))).count() == expl(2)); -static_assert(!std::is_constructible_v>, length>>); -static_assert(length>(quantity_cast(length>(2000))).count() == impl_impl(2)); -static_assert(!std::is_constructible_v>, length>>); -static_assert(length>(quantity_cast(length>(2000))).count() == impl_expl(2)); -static_assert(!std::is_constructible_v>, length>>); -static_assert(length>(quantity_cast(length>(expl_impl(2000)))).count() == expl_impl(2)); -static_assert(!std::is_constructible_v>, length>>); -static_assert(length>(quantity_cast(length>(expl_expl(2000)))).count() == expl_expl(2)); - -} // namespace diff --git a/test/unit_test/static/custom_rep_test_min_expl.cpp b/test/unit_test/static/custom_rep_test_min_expl.cpp new file mode 100644 index 00000000..bd2f7660 --- /dev/null +++ b/test/unit_test/static/custom_rep_test_min_expl.cpp @@ -0,0 +1,199 @@ +// 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 "units/physical/si/base/length.h" + +namespace { + +/** + * @brief Representation type meeting minimum requirements + * + * This type with a default Mode = 0 provides the minimum set of requirements to + * satisfy @c QuantityValue concept which is used for quantity's representation type. + * + * In case of Mode != 0 only one of mandatory operation is removed which should + * result in @c QuantityValue concept not being satisfied. + * + * @tparam Mode a flag to disable specific type's operations + */ +template +class min_expl { + std::intmax_t value_; +public: + // default construction + min_expl() requires (Mode != 1) = default; + + // construction from std::int64_t + explicit constexpr min_expl(std::intmax_t v) noexcept requires (Mode != 2) : value_(v) {} + + // copy construction + min_expl(const min_expl&) requires (Mode != 3) = default; + + // move construction + min_expl(min_expl&&) requires (Mode != 4) = default; + min_expl(min_expl&&) requires (Mode == 4) = delete; + + // copy assignment + min_expl& operator=(const min_expl&) requires (Mode != 5) = default; + + // move assignment + min_expl& operator=(min_expl&&) requires (Mode != 6) = default; + min_expl& operator=(min_expl&&) requires (Mode == 6) = delete; + + // equality + bool operator==(const min_expl&) const requires (Mode != 7) = default; + + // scalability - multiplication + friend constexpr min_expl operator*(const min_expl& lhs, const min_expl& rhs) requires (Mode != 8) + { return min_expl(lhs.value_ * rhs.value_); } + + // scalability - division + friend constexpr min_expl operator/(const min_expl& lhs, const min_expl& rhs) requires (Mode != 9) + { return min_expl(lhs.value_ / rhs.value_); } +}; + +} + +template +struct std::common_type> : std::type_identity> {}; +template +struct std::common_type, std::intmax_t> : std::type_identity> {}; + +namespace { + +using namespace units; +using namespace units::physical::si; + +// quantity explicitly constructible (not convertible) from the representation type +static_assert(std::constructible_from>, min_expl<>>); +static_assert(!std::convertible_to, length>>); + +// not constructible from an underlying type +static_assert(!std::constructible_from>, int>); +static_assert(!std::convertible_to>>); + +// dimensionless quantity implicitly convertible from the representation type +static_assert(std::constructible_from>, min_expl<>>); +static_assert(std::convertible_to, dimensionless>>); + +// but not from an underlying type +static_assert(!std::constructible_from>, int>); +static_assert(!std::convertible_to>>); + +// or for ratio != 1 +static_assert(std::constructible_from>, min_expl<>>); +static_assert(!std::convertible_to, dimensionless>>); + +// quantity convertible from itself +static_assert(std::constructible_from>, length>>); +static_assert(std::convertible_to>, length>>); + +// not convertible from an underlying type +static_assert(!std::constructible_from>, length>); +static_assert(!std::convertible_to, length>>); + +// quantity convertible from another non truncating unit +static_assert(std::constructible_from>, length>>); +static_assert(std::convertible_to>, length>>); + +// quantity not convertible from another truncating unit +static_assert(!std::constructible_from>, length>>); +static_assert(!std::convertible_to>, length>>); + +// rep type with explicit constructor - implicit construction of rep not allowed +static_assert(!std::constructible_from>, int>); +static_assert(!std::convertible_to>>); + +static_assert(!std::constructible_from>, length>); +static_assert(!std::convertible_to, length>>); + +static_assert(!std::constructible_from, min_expl<>>); +static_assert(!std::convertible_to, length>); + +static_assert(!std::constructible_from, length>>); +static_assert(!std::convertible_to>, length>); + +// all operations needed to satisfy concept +static_assert(QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); +static_assert(!QuantityValue>); + +// quantity's operators should mirror the representation type capabilities +template +concept invalid_member_operations = requires(length lhs) { + requires !requires { +lhs; }; + requires !requires { -lhs; }; + requires !requires { ++lhs; }; + requires !requires { lhs++; }; + requires !requires { --lhs; }; + requires !requires { lhs--; }; + + requires !requires(length rhs) { lhs += rhs; }; + requires !requires(length rhs) { lhs -= rhs; }; + requires !requires(Rep rhs) { lhs *= rhs; }; + requires !requires(Rep rhs) { lhs /= rhs; }; + requires !requires(Rep rhs) { lhs %= rhs; }; + requires !requires(length rhs) { lhs %= rhs; }; + + requires !requires(length rhs) { lhs + rhs; }; + requires !requires(length rhs) { lhs - rhs; }; + requires !requires(Rep rhs) { lhs % rhs; }; + requires !requires(length rhs) { lhs % rhs; }; + requires !requires(length rhs) { lhs < rhs; }; + requires !requires(length rhs) { lhs > rhs; }; + requires !requires(length rhs) { lhs <= rhs; }; + requires !requires(length rhs) { lhs >= rhs; }; + + requires !requires(length rhs) { lhs + rhs; }; + requires !requires(length rhs) { lhs - rhs; }; + requires !requires(int rhs) { lhs % rhs; }; + requires !requires(length rhs) { lhs % rhs; }; + requires !requires(length rhs) { lhs == rhs; }; + requires !requires(length rhs) { lhs != rhs; }; + requires !requires(length rhs) { lhs < rhs; }; + requires !requires(length rhs) { lhs > rhs; }; + requires !requires(length rhs) { lhs <= rhs; }; + requires !requires(length rhs) { lhs >= rhs; }; + + requires !requires(std::ostream os) { os << lhs; }; +}; +static_assert(invalid_member_operations>); + +// equality +static_assert(length>(min_expl<>(2)) == length>(min_expl<>(2000))); +static_assert(length>(min_expl<>(123)) * min_expl<>(2) == length>(min_expl<>(246))); +static_assert(length>(min_expl<>(123)) * quantity{min_expl<>(2)} == length>(min_expl<>(246))); +static_assert(min_expl<>(2) * length>(min_expl<>(123)) == length>(min_expl<>(246))); +static_assert(quantity{min_expl<>(2)} * length>(min_expl<>(123)) == length>(min_expl<>(246))); +static_assert(length>(min_expl<>(246)) / min_expl<>(2) == length>(min_expl<>(123))); +static_assert(length>(min_expl<>(246)) / quantity{min_expl<>(2)} == length>(min_expl<>(123))); +static_assert(length>(min_expl<>(246)) / length>(min_expl<>(2)) == quantity{min_expl<>(123)}); +static_assert(length>(min_expl<>(246)) / length>(min_expl<>(2)) == min_expl<>(123)); + +} // namespace diff --git a/test/unit_test/static/custom_rep_test_min_impl.cpp b/test/unit_test/static/custom_rep_test_min_impl.cpp new file mode 100644 index 00000000..ee756551 --- /dev/null +++ b/test/unit_test/static/custom_rep_test_min_impl.cpp @@ -0,0 +1,317 @@ +// 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 "units/math.h" +#include "units/physical/si/base/length.h" +#include +#include +#include + +namespace { + +/** + * @brief Implicitly constructible and convertible representation type + * + * A wrapper type that is implicitly convertible from and to the contained type. + * + * @tparam T element type + */ +template +class min_impl { + T value_; +public: + using value_type = T; + + min_impl() = default; + constexpr min_impl(T v) noexcept : value_(v) {} + template + constexpr min_impl(min_impl i) noexcept : value_(static_cast(i.value_)) {} + constexpr operator T() const noexcept { return value_; } +}; + +} + +template +struct std::common_type, min_impl> : std::common_type {}; +template +struct std::common_type, U> : std::common_type {}; +template +struct std::common_type> : std::common_type {}; + +namespace { + +using namespace units; +using namespace units::physical::si; + +static_assert(QuantityValue>); +static_assert(QuantityValue>); + +// construction from a value +static_assert(std::constructible_from>, min_impl>); +static_assert(!std::convertible_to, length>>); + +static_assert(std::constructible_from>, min_impl>); +static_assert(!std::convertible_to, length>>); + +static_assert(std::constructible_from>, min_impl>); +static_assert(!std::convertible_to, length>>); + +static_assert(!std::constructible_from>, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, length>>); + +// construction from an underlying type +static_assert(std::constructible_from>, int>); +static_assert(!std::convertible_to>>); + +static_assert(std::constructible_from>, double>); +static_assert(!std::convertible_to>>); + +static_assert(std::constructible_from>, int>); +static_assert(!std::convertible_to>>); + +static_assert(!std::constructible_from>, double>); // narrowing conversion +static_assert(!std::convertible_to>>); + +// dimensionless quantity is convertible from a value +static_assert(std::constructible_from>, min_impl>); +static_assert(std::convertible_to, dimensionless>>); + +static_assert(std::constructible_from>, min_impl>); +static_assert(std::convertible_to, dimensionless>>); + +static_assert(std::constructible_from>, min_impl>); +static_assert(std::convertible_to, dimensionless>>); + +static_assert(!std::constructible_from>, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, dimensionless>>); + +// and underlying type +static_assert(std::constructible_from>, int>); +static_assert(std::convertible_to>>); + +static_assert(std::constructible_from>, double>); +static_assert(std::convertible_to>>); + +static_assert(std::constructible_from>, int>); +static_assert(std::convertible_to>>); + +static_assert(!std::constructible_from>, double>); // narrowing conversion +static_assert(!std::convertible_to>>); + +// but only for ratio(1), otherwise not convertible +static_assert(std::constructible_from>, min_impl>); +static_assert(!std::convertible_to, dimensionless>>); + +static_assert(std::constructible_from>, min_impl>); +static_assert(!std::convertible_to, dimensionless>>); + +static_assert(std::constructible_from>, min_impl>); +static_assert(!std::convertible_to, dimensionless>>); + +static_assert(!std::constructible_from>, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, dimensionless>>); + +// implicit conversion tests +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, length>); + +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, length>); + +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, length>); + +static_assert(!std::constructible_from, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, length>); + +// construction from an underlying type +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, length>); + +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, length>); + +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, length>); + +static_assert(!std::constructible_from, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, length>); + +// dimensionless quantity is convertible from a value +static_assert(std::constructible_from, min_impl>); +static_assert(std::convertible_to, dimensionless>); + +static_assert(std::constructible_from, min_impl>); +static_assert(std::convertible_to, dimensionless>); + +static_assert(std::constructible_from, min_impl>); +static_assert(std::convertible_to, dimensionless>); + +static_assert(!std::constructible_from, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, dimensionless>); + +// but only for ratio(1), otherwise not convertible +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, dimensionless>); + +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, dimensionless>); + +static_assert(std::constructible_from, min_impl>); +static_assert(!std::convertible_to, dimensionless>); + +static_assert(!std::constructible_from, min_impl>); // narrowing conversion +static_assert(!std::convertible_to, dimensionless>); + +// construction from a quantity +// min_impl -> min_impl +static_assert(std::constructible_from>, length>>); +static_assert(std::convertible_to>, length>>); + +static_assert(std::constructible_from>, length>>); +static_assert(std::convertible_to>, length>>); + +static_assert(std::constructible_from>, length>>); +static_assert(std::convertible_to>, length>>); + +static_assert(!std::constructible_from>, length>>); // narrowing conversion +static_assert(!std::convertible_to>, length>>); + +// T -> min_impl +static_assert(std::constructible_from>, length>); +static_assert(std::convertible_to, length>>); + +static_assert(std::constructible_from>, length>); +static_assert(std::convertible_to, length>>); + +static_assert(std::constructible_from>, length>); +static_assert(std::convertible_to, length>>); + +static_assert(!std::constructible_from>, length>); // narrowing conversion +static_assert(!std::convertible_to, length>>); + +// min_impl -> T +static_assert(std::constructible_from, length>>); +static_assert(std::convertible_to>, length>); + +static_assert(std::constructible_from, length>>); +static_assert(std::convertible_to>, length>); + +static_assert(std::constructible_from, length>>); +static_assert(std::convertible_to>, length>); + +static_assert(!std::constructible_from, length>>); // narrowing conversion +static_assert(!std::convertible_to>, length>); + + +// arithmetic operators +static_assert(length>(1) + length>(1) == length>(2)); +static_assert(length>(1) + length>(1.5) == length>(2.5)); +static_assert(length(1) + length>(1) == length>(2)); +static_assert(length(1) + length>(1.5) == length>(2.5)); +static_assert(length>(1) + length(1) == length>(2)); +static_assert(length>(1) + length(1.5) == length>(2.5)); +static_assert(length>(1) + length>(1) == length(2)); +static_assert(length>(1) + length>(1.5) == length(2.5)); + +static_assert(length>(1) + length>(1) == length>(1001)); +static_assert(length>(1) + length>(1.5) == length>(1001.5)); +static_assert(length(1) + length>(1) == length>(1001)); +static_assert(length(1) + length>(1.5) == length>(1001.5)); +static_assert(length>(1) + length(1) == length>(1001)); +static_assert(length>(1) + length(1.5) == length>(1001.5)); +static_assert(length>(1) + length>(1) == length(1001)); +static_assert(length>(1) + length>(1.5) == length(1001.5)); + +static_assert(length>(1) + length>(1) == length>(1001)); +static_assert(length>(1) + length>(1.5) == length>(1501)); +static_assert(length(1) + length>(1) == length>(1001)); +static_assert(length(1) + length>(1.5) == length>(1501)); +static_assert(length>(1) + length(1) == length>(1001)); +static_assert(length>(1) + length(1.5) == length>(1501)); +static_assert(length>(1) + length>(1) == length(1001)); +static_assert(length>(1) + length>(1.5) == length(1501)); + +static_assert(length>(2) - length>(1) == length>(1)); +static_assert(length>(2) - length>(1.5) == length>(0.5)); +static_assert(length(2) - length>(1) == length>(1)); +static_assert(length(2) - length>(1.5) == length>(0.5)); +static_assert(length>(2) - length(1) == length>(1)); +static_assert(length>(2) - length(1.5) == length>(0.5)); +static_assert(length>(2) - length>(1) == length(1)); +static_assert(length>(2) - length>(1.5) == length(0.5)); + +static_assert(length>(2) - length>(1) == length>(1999)); +static_assert(length>(2) - length>(1.5) == length>(1998.5)); +static_assert(length(2) - length>(1) == length>(1999)); +static_assert(length(2) - length>(1.5) == length>(1998.5)); +static_assert(length>(2) - length(1) == length>(1999)); +static_assert(length>(2) - length(1.5) == length>(1998.5)); +static_assert(length>(2) - length>(1) == length(1999)); +static_assert(length>(2) - length>(1.5) == length(1998.5)); + +static_assert(length>(2000) - length>(1) == length>(1000)); +static_assert(length>(2000) - length>(1.5) == length>(500)); +static_assert(length(2000) - length>(1) == length>(1000)); +static_assert(length(2000) - length>(1.5) == length>(500)); +static_assert(length>(2000) - length(1) == length>(1000)); +static_assert(length>(2000) - length(1.5) == length>(500)); +static_assert(length>(2000) - length>(1) == length(1000)); +static_assert(length>(2000) - length>(1.5) == length(500)); + +static_assert(length>(123) * min_impl(1.5) == length>(184.5)); +static_assert(length>(123) * 1.5 == length>(184.5)); +static_assert(length(123) * min_impl(1.5) == length>(184.5)); + +static_assert(length>(123) * quantity{min_impl(1.5)} == length>(184.5)); +static_assert(length>(123) * quantity{1.5} == length>(184.5)); +static_assert(length(123) * quantity{min_impl(1.5)} == length>(184.5)); + +static_assert(min_impl(1.5) * length>(123) == length>(184.5)); +static_assert(min_impl(1.5) * length(123) == length>(184.5)); +static_assert(1.5 * length>(123) == length>(184.5)); + +static_assert(quantity{min_impl(1.5)} * length>(123) == length>(184.5)); +static_assert(quantity{min_impl(1.5)} * length(123) == length>(184.5)); +static_assert(quantity{1.5} * length>(123) == length>(184.5)); + +static_assert(length>(123) / min_impl(2.) == length>(61.5)); +static_assert(length>(123) / 2. == length>(61.5)); +static_assert(length(123) / min_impl(2.) == length>(61.5)); + +static_assert(length>(123) / quantity{min_impl(2.)} == length>(61.5)); +static_assert(length>(123) / quantity{2.} == length>(61.5)); +static_assert(length(123) / quantity{min_impl(2.)} == length>(61.5)); + +static_assert(length>(123) / length>(2.) == 61.5); +static_assert(length>(123) / length(2.) == 61.5); +static_assert(length(123) / length>(2.) == 61.5); + +static_assert(length>(123) % min_impl(100) == length(23)); +static_assert(length>(123) % 100 == length(23)); +static_assert(length(123) % min_impl(100) == length(23)); + +static_assert(length>(123) % quantity{min_impl(100)} == length(23)); +static_assert(length>(123) % quantity{100} == length(23)); +static_assert(length(123) % quantity{min_impl(100)} == length(23)); + +} // namespace diff --git a/test/unit_test/static/custom_unit_test.cpp b/test/unit_test/static/custom_unit_test.cpp index 15846639..67c92af9 100644 --- a/test/unit_test/static/custom_unit_test.cpp +++ b/test/unit_test/static/custom_unit_test.cpp @@ -36,14 +36,14 @@ using namespace units::physical::si; struct sq_volt_per_hertz : unit {}; struct dim_power_spectral_density : derived_dimension, units::exponent> {}; -template +template U, QuantityValue Rep = double> using power_spectral_density = quantity; // amplitude spectral density struct volt_per_sqrt_hertz : unit {}; struct dim_amplitude_spectral_density : derived_dimension, units::exponent> {}; -template +template U, QuantityValue Rep = double> using amplitude_spectral_density = quantity; } diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index b1fb2fbe..1ab8e6e7 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -22,9 +22,16 @@ #include "test_tools.h" #include "units/math.h" -#include "units/physical/si/si.h" -#include "units/physical/si/us/us.h" +#include "units/physical/si/cgs/derived/speed.h" +#include "units/physical/si/derived/area.h" +#include "units/physical/si/derived/frequency.h" +#include "units/physical/si/derived/speed.h" +#include "units/physical/si/derived/volume.h" +#include "units/physical/si/fps/derived/speed.h" #include +#include +#include +#include #include namespace { @@ -32,54 +39,67 @@ namespace { using namespace units; using namespace units::physical::si; -// class invariants -template -concept invalid_types = requires -{ - requires !requires { typename quantity; }; // unit of a different dimension - requires !requires { typename quantity>; }; // quantity used as Rep - requires !requires { typename quantity; }; // reordered arguments +////////////////////////////// +// quantity class invariants +////////////////////////////// + +static_assert(sizeof(length) == sizeof(double)); +static_assert(sizeof(length) == sizeof(short)); + +#if COMP_GCC != 10 || COMP_GCC_MINOR != 2 // TODO remove when gcc 10.3 releases +template typename Q> +concept invalid_types = requires { + requires !requires { typename Q; }; // unit of a different dimension + requires !requires { typename Q>; }; // quantity used as Rep + requires !requires { typename Q; }; // reordered arguments + requires !requires { typename Q; }; // reordered arguments }; +static_assert(invalid_types); +#endif -static_assert(invalid_types); +static_assert(std::is_trivially_default_constructible_v>); +static_assert(std::is_trivially_copy_constructible_v>); +static_assert(std::is_trivially_move_constructible_v>); +static_assert(std::is_trivially_copy_assignable_v>); +static_assert(std::is_trivially_move_assignable_v>); +static_assert(std::is_trivially_destructible_v>); +static_assert(std::is_nothrow_default_constructible_v>); +static_assert(std::is_nothrow_copy_constructible_v>); +static_assert(std::is_nothrow_move_constructible_v>); +static_assert(std::is_nothrow_copy_assignable_v>); +static_assert(std::is_nothrow_move_assignable_v>); +static_assert(std::is_nothrow_destructible_v>); + +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_standard_layout_v>); + +static_assert(std::default_initializable>); +static_assert(std::move_constructible>); +static_assert(std::copy_constructible>); +static_assert(std::equality_comparable>); +static_assert(std::totally_ordered>); +static_assert(std::regular>); + +static_assert(std::three_way_comparable>); + + +////////////////// // member types +////////////////// -static_assert(is_same_v::rep, int>); -static_assert(is_same_v::rep, double>); +static_assert(is_same_v::dimension, dim_length>); +static_assert(is_same_v::dimension, fps::dim_length>); static_assert(is_same_v::unit, metre>); -static_assert(is_same_v::unit, kilometre>); +static_assert(is_same_v::unit, fps::mile>); +static_assert(is_same_v::rep, int>); +static_assert(is_same_v::rep, double>); -// constructors - -static_assert(length().count() == 0); -constexpr length km{1000}; -static_assert(km.count() == 1000); -static_assert(length(km).count() == km.count()); - -static_assert(length(1).count() == 1); -static_assert(!std::is_constructible_v, double>); // truncating conversion -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(!std::is_constructible_v, - length>); // truncating conversion -static_assert(length(1000.0_q_m).count() == 1000.0); -static_assert(length(km).count() == 1000.0); -static_assert(length(1_q_km).count() == 1000); -static_assert(!std::is_constructible_v, - physical::si::time>); // different dimensions -static_assert(!std::is_constructible_v, - length>); // truncating conversion - -// assignment operator - -static_assert([]() { length l1(1), l2(2); return l2 = l1; }().count() == 1); +//////////////////////////// // static member functions +//////////////////////////// static_assert(length::zero().count() == 0); static_assert(length::min().count() == std::numeric_limits::lowest()); @@ -88,32 +108,165 @@ 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 -static_assert((+km).count() == 1000); -static_assert((-km).count() == -1000); -static_assert((+(-km)).count() == -1000); -static_assert((-(-km)).count() == 1000); +////////////////////////////// +// construction from a value +////////////////////////////// -static_assert([](auto v) { - auto vv = v++; - return std::pair(v, vv); -}(km) == std::pair(length(1001), length(1000))); -static_assert([](auto v) { - auto vv = ++v; - return std::pair(v, vv); -}(km) == std::pair(length(1001), length(1001))); -static_assert([](auto v) { - auto vv = v--; - return std::pair(v, vv); -}(km) == std::pair(length(999), length(1000))); -static_assert([](auto v) { - auto vv = --v; - return std::pair(v, vv); -}(km) == std::pair(length(999), length(999))); +// only explicit construction from a value +static_assert(std::constructible_from, double>); +static_assert(!std::convertible_to>); +static_assert(std::constructible_from, float>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, double>); // truncating implicit conversions double -> float allowed +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, int>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, short>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, int>); // truncating implicit conversions int -> short allowed +static_assert(!std::convertible_to>); + +// exception, implicit construction from a value allowed for a dimensionless quantity +static_assert(std::constructible_from, double>); +static_assert(std::convertible_to>); + +static_assert(std::constructible_from, float>); +static_assert(std::convertible_to>); + +static_assert(std::constructible_from, double>); +static_assert(std::convertible_to>); + +static_assert(std::constructible_from, int>); +static_assert(std::convertible_to>); + +static_assert(std::constructible_from, short>); +static_assert(std::convertible_to>); + +static_assert(std::constructible_from, int>); +static_assert(std::convertible_to>); + +// but only if a dimensionless quantity has a ratio(1) +static_assert(std::constructible_from, double>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, float>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, double>); // truncating implicit conversions double -> float allowed +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, int>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, short>); +static_assert(!std::convertible_to>); + +static_assert(std::constructible_from, int>); // truncating implicit conversions int -> short allowed +static_assert(!std::convertible_to>); + +// floating-point to integral truncating conversion not allowed +static_assert(!std::constructible_from, double>); +static_assert(!std::convertible_to>); + +static_assert(!std::constructible_from, double>); +static_assert(!std::convertible_to>); + +static_assert(length().count() == 0); // value initialization +static_assert(length(1).count() == 1); +static_assert(length(1.0).count() == 1.0); +static_assert(length(1).count() == 1.0); +static_assert(length(3.14).count() == 3.14); + + +/////////////////////////////////////// +// construction from another quantity +/////////////////////////////////////// + +// conversion only between equivalent dimensions +static_assert(std::constructible_from, length>); +static_assert(std::convertible_to, length>); +static_assert(std::constructible_from, cgs::length>); +static_assert(std::convertible_to, length>); +static_assert(std::constructible_from, cgs::length>); +static_assert(std::convertible_to, fps::length>); + +// conversion between different dimensions not allowed +static_assert(!std::constructible_from, physical::si::time>); +static_assert(!std::convertible_to, length>); +static_assert(!std::constructible_from, speed>); +static_assert(!std::convertible_to, length>); + +// implicit conversion from another quantity only if non-truncating +static_assert(std::constructible_from, length>); // int -> double OK +static_assert(std::convertible_to, length>); // int -> double OK + +static_assert(!std::constructible_from, length>); // truncating double -> int not allowed +static_assert(!std::convertible_to, length>); // truncating double -> int not allowed + +static_assert(std::constructible_from, length>); // kilometre -> metre OK +static_assert(std::convertible_to, length>); // kilometre -> metre OK + +static_assert(!std::constructible_from, length>); // truncating metre -> kilometre not allowed +static_assert(!std::convertible_to, length>); // truncating metre -> kilometre not allowed + +// converting to double always OK +static_assert(std::constructible_from, length>); +static_assert(std::convertible_to, length>); +static_assert(std::constructible_from, length>); +static_assert(std::convertible_to, length>); + +static_assert(length(123_q_m).count() == 123); +static_assert(length(2_q_km).count() == 2); +static_assert(length(2_q_km).count() == 2000); +static_assert(length(1500_q_m).count() == 1.5); + + +///////// +// CTAD +///////// + +static_assert(std::is_same_v(123)}), length>); +static_assert(std::is_same_v(123)}), speed>); +// static_assert(std::is_same_v(123)}), length>); // TODO gcc ICE +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + + +//////////////////////// +// assignment operator +//////////////////////// + +static_assert([]() { length l1(1), l2(2); return l2 = l1; }().count() == 1); +static_assert([]() { length l1(1), l2(2); return l2 = std::move(l1); }().count() == 1); + + +//////////////////// +// unary operators +//////////////////// + +static_assert((+123_q_m).count() == 123); +static_assert((-123_q_m).count() == -123); +static_assert((+(-123_q_m)).count() == -123); +static_assert((-(-123_q_m)).count() == 123); + +static_assert([](auto v) { auto vv = v++; return std::pair(v, vv); }(123_q_m) == std::pair(124_q_m, 123_q_m)); +static_assert([](auto v) { auto vv = ++v; return std::pair(v, vv); }(123_q_m) == std::pair(124_q_m, 124_q_m)); +static_assert([](auto v) { auto vv = v--; return std::pair(v, vv); }(123_q_m) == std::pair(122_q_m, 123_q_m)); +static_assert([](auto v) { auto vv = --v; return std::pair(v, vv); }(123_q_m) == std::pair(122_q_m, 122_q_m)); + + +//////////////////////// // compound assignment +//////////////////////// +// same type static_assert((1_q_m += 1_q_m).count() == 2); static_assert((2_q_m -= 1_q_m).count() == 1); static_assert((1_q_m *= 2).count() == 2); @@ -121,190 +274,372 @@ static_assert((2_q_m /= 2).count() == 1); static_assert((7_q_m %= 2).count() == 1); static_assert((7_q_m %= 2_q_m).count() == 1); +// different types static_assert((2.5_q_m += 3_q_m).count() == 5.5); -static_assert((2.5_q_m += 3.5_q_m).count() == 6); - +static_assert((123_q_m += 1_q_km).count() == 1123); +static_assert((5.5_q_m -= 3_q_m).count() == 2.5); +static_assert((1123_q_m -= 1_q_km).count() == 123); static_assert((2.5_q_m *= 3).count() == 7.5); -static_assert((2.5_q_m *= 3.5).count() == 8.75); +static_assert((7.5_q_m /= 3).count() == 2.5); +static_assert((3500_q_m %= 1_q_km).count() == 500); -// operations not allowed for the respective quantities template -concept invalid_compound_assignments = requires() -{ +concept invalid_compound_assignments = requires() { + // truncating not allowed + requires !requires(length l) { l += 2.5_q_m; }; + requires !requires(length l) { l -= 2.5_q_m; }; + requires !requires(length l) { l += length(2); }; + requires !requires(length l) { l -= length(2); }; + requires !requires(length l) { l %= length(2); }; + + // only quantities can be added or subtracted + requires !requires(length l) { l += 2; }; + requires !requires(length l) { l -= 2; }; + + // compound multiply/divide by another quantity not allowed + requires !requires(length l) { l *= 2_q_m; }; + requires !requires(length l) { l /= 2_q_m; }; + + // modulo operations on a floating point representation not allowed requires !requires(length l) { l %= 2.; }; requires !requires(length l) { l %= 2; }; - requires !requires(length l) { l %= 2.; }; requires !requires(length l) { l %= 2._q_m; }; requires !requires(length l) { l %= 2_q_m; }; requires !requires(length l) { l %= 2._q_m; }; - requires !requires(length l) { l += 3.5_q_m; }; - requires !requires(length l) { l *= 3.5_q_m; }; }; - static_assert(invalid_compound_assignments); -// non-member arithmetic operators -static_assert(compare() + length()), length>); -static_assert(compare() + length()), length>); -static_assert(compare() + length()), length>); -static_assert(compare() - length()), length>); -static_assert(compare() - length()), length>); -static_assert(compare() * 1.0), length>); -static_assert(compare()), length>); -static_assert( - compare() * physical::si::time()), length>); -static_assert( - compare() * physical::si::time()), length, int>>); -static_assert(compare() * physical::si::time()), - quantity, units::exponent>, scaled_unit>>); -static_assert(compare()), frequency>); -static_assert(compare()), frequency, int>>); -static_assert(compare()), physical::si::time>); -static_assert(compare()), - quantity>, scaled_unit>>); -static_assert(compare() / 1.0), length>); -static_assert(compare() / length()), dimensionless>); -static_assert(compare() / length()), dimensionless, double>>); -static_assert( - compare() / physical::si::time()), speed>); -static_assert( - compare() / physical::si::time()), speed>>); -static_assert(compare() / length()), - quantity, units::exponent>, scaled_unit>>); -static_assert(compare() % short(1)), length>); -static_assert(compare() % length(1)), length>); +//////////////////// +// binary operators +//////////////////// -static_assert((1_q_m + km).count() == 1001); +template +concept invalid_binary_operations = requires { + // no crossdimensional addition and subtraction + requires !requires { 1_q_s + length(1); }; + requires !requires { 1_q_s - length(1); }; + + // no floating-point modulo + requires !requires(length a) { a % 2_q_m; }; + requires !requires(length a) { 2_q_m % a; }; + requires !requires(length a) { a % 2; }; + requires !requires(length a, length b) { a % b; }; + requires !requires(length a, length b) { a % b; }; + requires !requires(length a, length b) { b % a; }; +}; +static_assert(invalid_binary_operations); + +// same representation type +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(compare(1)), length>); +static_assert(compare(1) * 1_q_m), length>); +static_assert(compare(1)), length>); +static_assert(compare(1)), length>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare(1) / 1_q_s), frequency, std::int64_t>>); + +// different representation types +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); // TODO should we address fundamental types implicit truncating conversions with concepts? +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); // TODO should we address fundamental types implicit truncating conversions with concepts? +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(compare(1)), length>); +static_assert(compare(1) * 1._q_m), length>); +static_assert(compare>); +static_assert(compare(1)), length>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare(1) / 1._q_s), frequency, long double>>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare(1)), length>); +static_assert(compare(1)), length>); + +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(compare(1)), length>); +static_assert(compare(1) * 1_q_m), length>); +static_assert(compare(1)), length>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare>); +static_assert(compare(1) / 1_q_s), frequency, long double>>); + +// different units +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +// different dimensions +static_assert(compare>); +static_assert(compare, std::int64_t>>); +static_assert(compare, exponent>, scaled_unit, std::int64_t>>); +static_assert(compare>); +static_assert(compare, std::int64_t>>); +static_assert(compare>); +static_assert(compare>, scaled_unit, std::int64_t>>); +static_assert(compare, std::int64_t>>); +static_assert(compare>); +static_assert(compare, std::int64_t>>); +static_assert(compare, exponent>, scaled_unit, std::int64_t>>); + +static_assert((1_q_m + 1_q_m).count() == 2); static_assert((1_q_m + 1_q_km).count() == 1001); -static_assert((km - 1_q_m).count() == 999); +static_assert((1_q_km + 1_q_m).count() == 1001); +static_assert((2_q_m - 1_q_m).count() == 1); static_assert((1_q_km - 1_q_m).count() == 999); static_assert((2_q_m * 2).count() == 4); +static_assert((2_q_m * quantity{2}).count() == 4); +static_assert((2_q_m * dimensionless(2)).count() == 4); static_assert((3 * 3_q_m).count() == 9); +static_assert((quantity{3} * 3_q_m).count() == 9); +static_assert((dimensionless(3) * 3_q_m).count() == 9); static_assert((4_q_m / 2).count() == 2); +static_assert((4_q_m / quantity{2}).count() == 2); +static_assert((4_q_m / dimensionless(2)).count() == 2); static_assert((4_q_km / 2_q_m).count() == 2); static_assert((4000_q_m / 2_q_m).count() == 2000); + +static_assert((1.5_q_m + 1_q_m).count() == 2.5); +static_assert((1.5_q_m + 1_q_km).count() == 1001.5); +static_assert((1.5_q_km + 1_q_m).count() == 1501); +static_assert((2.5_q_m - 1_q_m).count() == 1.5); +static_assert((1.5_q_km - 1_q_m).count() == 1499); +static_assert((2.5_q_m * 2).count() == 5); +static_assert((2.5_q_m * quantity{2}).count() == 5); +static_assert((2.5_q_m * dimensionless(2)).count() == 5); +static_assert((2.5L * 2_q_m).count() == 5); +static_assert((quantity{2.5L} * 2_q_m).count() == 5); +static_assert((dimensionless(2.5L) * 2_q_m).count() == 5); +static_assert((5._q_m / 2).count() == 2.5); +static_assert((5._q_m / quantity{2}).count() == 2.5); +static_assert((5._q_m / dimensionless(2)).count() == 2.5); +static_assert((5._q_km / 2_q_m).count() == 2.5); +static_assert((5000._q_m / 2_q_m).count() == 2500); + +static_assert((1_q_m + 1.5_q_m).count() == 2.5); +static_assert((1_q_m + 1.5_q_km).count() == 1501); +static_assert((1_q_km + 1.5_q_m).count() == 1001.5); +static_assert((2_q_m - 1.5_q_m).count() == 0.5); +static_assert((1_q_km - 1.5_q_m).count() == 998.5); +static_assert((2_q_m * 2.5L).count() == 5); +static_assert((2_q_m * quantity{2.5L}).count() == 5); +static_assert((2_q_m * dimensionless(2.5L)).count() == 5); +static_assert((2 * 2.5_q_m).count() == 5); +static_assert((quantity{2} * 2.5_q_m).count() == 5); +static_assert((dimensionless(2) * 2.5_q_m).count() == 5); +static_assert((5_q_m / 2.5L).count() == 2); +static_assert((5_q_m / quantity{2.5L}).count() == 2); +static_assert((5_q_m / dimensionless(2.5L)).count() == 2); +static_assert((5_q_km / 2.5_q_m).count() == 2); +static_assert((5000_q_m / 2.5_q_m).count() == 2000); + static_assert((7_q_m % 2).count() == 1); +static_assert((7_q_m % quantity{2}).count() == 1); +static_assert((7_q_m % dimensionless(2)).count() == 1); static_assert((7_q_m % 2_q_m).count() == 1); static_assert((7_q_km % 2000_q_m).count() == 1000); static_assert((10_q_km2 * 10_q_km2) / 50_q_km2 == 2_q_km2); -constexpr auto q1 = 10_q_km / 5_q_m; -static_assert(compare, std::int64_t>>); -static_assert(q1.count() == 2); - -constexpr dimensionless q2 = q1; -static_assert(q2.count() == 2000); +static_assert((10_q_km / 5_q_m).count() == 2); +static_assert(dimensionless(10_q_km / 5_q_m).count() == 2000); #if UNITS_DOWNCAST_MODE == 0 -static_assert(quantity_cast(q1).count() == 2000); +static_assert(quantity_cast(10_q_km / 5_q_m).count() == 2000); #else -static_assert(quantity_cast(q1).count() == 2000); +static_assert(quantity_cast(10_q_km / 5_q_m).count() == 2000); #endif -constexpr auto q3 = 10_q_s * 2_q_kHz; -static_assert(compare, std::int64_t>>); -static_assert(q3.count() == 20); +static_assert((10_q_s * 2_q_kHz).count() == 20); -// comparators -static_assert(2_q_m + 1_q_m == 3_q_m); -static_assert(!(2_q_m + 2_q_m == 3_q_m)); -static_assert(2_q_m + 2_q_m != 3_q_m); -static_assert(!(2_q_m + 2_q_m != 4_q_m)); -static_assert(2_q_m > 1_q_m); -static_assert(!(1_q_m > 1_q_m)); -static_assert(1_q_m < 2_q_m); -static_assert(!(2_q_m < 2_q_m)); -static_assert(2_q_m >= 1_q_m); -static_assert(2_q_m >= 2_q_m); -static_assert(!(2_q_m >= 3_q_m)); -static_assert(1_q_m <= 2_q_m); -static_assert(2_q_m <= 2_q_m); -static_assert(!(3_q_m <= 2_q_m)); +// dimensionless -static_assert(3_q_m == 3.0_q_m); -static_assert(3_q_m != 3.14_q_m); -static_assert(2_q_m > 1.0_q_m); -static_assert(1.0_q_m < 2_q_m); -static_assert(2.0_q_m >= 1_q_m); -static_assert(1_q_m <= 2.0_q_m); +static_assert(quantity{1} + quantity{1} == 2); +static_assert(1 + quantity{1} == 2); +static_assert(quantity{1} + 1 == 2); +static_assert(quantity{2} - quantity{1} == 1); +static_assert(2 - quantity{1} == 1); +static_assert(quantity{2} - 1 == 1); +static_assert(quantity{2} * quantity{2} == 4); +static_assert(2 * quantity{2} == 4); +static_assert(quantity{2} * 2 == 4); +static_assert(quantity{4} / quantity{2} == 2); +static_assert(4 / quantity{2} == 2); +static_assert(quantity{4} / 2 == 2); +static_assert(quantity{4} % quantity{2} == 0); +static_assert(4 % quantity{2} == 0); +static_assert(quantity{4} % 2 == 0); -static_assert(1000_q_m == 1_q_km); -static_assert(1001_q_m != 1_q_km); -static_assert(1001_q_m > 1_q_km); -static_assert(999_q_m < 1_q_km); -static_assert(1000_q_m >= 1_q_km); -static_assert(1000_q_m <= 1_q_km); -// alias units +/////////////////////// +// equality operators +/////////////////////// -static_assert(2_q_l + 2_q_ml == 2002_q_ml); -static_assert(2_q_l + 2_q_ml == 2002_q_cm3); -static_assert(2_q_l + 2_q_cm3 == 2002_q_ml); -static_assert(2_q_dm3 + 2_q_cm3 == 2002_q_ml); +template +concept no_crossdimensional_equality = requires { + requires !requires { 1_q_s == length(1); }; + requires !requires { 1_q_s != length(1); }; +}; +static_assert(no_crossdimensional_equality); -// is_quantity +// same type +static_assert(length(123) == length(123)); +static_assert(length(321) != length(123)); +static_assert(!(length(123) == length(321))); +static_assert(!(length(123) != length(123))); -static_assert(Quantity>); +// different types +static_assert(length(123) == length(123)); +static_assert(length(321) != length(123)); +static_assert(!(length(123) == length(321))); +static_assert(!(length(123) != length(123))); -// common_quantity +static_assert(length(123) == length(123000)); +static_assert(length(321) != length(123000)); +static_assert(!(length(123) == length(321000))); +static_assert(!(length(123) != length(123000))); -static_assert(compare, length>, length>); -static_assert(compare, length>, length>); -static_assert( - compare, length>, length>); +// dimensionless -// common_type +static_assert(quantity{123} == 123); +static_assert(quantity{321} != 123); +static_assert(123 == quantity{123}); +static_assert(123 != quantity{321}); -using namespace units::physical::si::us::literals; -static_assert(std::equality_comparable); -static_assert(std::equality_comparable_with); -static_assert(0_q_m == 0_q_ft_us); -static_assert(std::equality_comparable_with); +/////////////////////// +// ordering operators +/////////////////////// + +template +concept no_crossdimensional_ordering = requires { + requires !requires { 1_q_s < length(1); }; + requires !requires { 1_q_s > length(1); }; + requires !requires { 1_q_s <= length(1); }; + requires !requires { 1_q_s >= length(1); }; +}; +static_assert(no_crossdimensional_ordering); + +// same type +static_assert(length(123) < length(321)); +static_assert(length(123) <= length(123)); +static_assert(length(123) <= length(321)); +static_assert(length(321) > length(123)); +static_assert(length(123) >= length(123)); +static_assert(length(321) >= length(123)); +static_assert(!(length(321) < length(123))); +static_assert(!(length(123) < length(123))); +static_assert(!(length(321) <= length(123))); +static_assert(!(length(123) > length(321))); +static_assert(!(length(123) > length(123))); +static_assert(!(length(123) >= length(321))); + +// different types +static_assert(length(123) < length(321)); +static_assert(length(123) <= length(123)); +static_assert(length(123) <= length(321)); +static_assert(length(321) > length(123)); +static_assert(length(123) >= length(123)); +static_assert(length(321) >= length(123)); +static_assert(!(length(321) < length(123))); +static_assert(!(length(123) < length(123))); +static_assert(!(length(321) <= length(123))); +static_assert(!(length(123) > length(321))); +static_assert(!(length(123) > length(123))); +static_assert(!(length(123) >= length(321))); + +static_assert(length(123) < length(321000)); +static_assert(length(123) <= length(123000)); +static_assert(length(123) <= length(321000)); +static_assert(length(321) > length(123000)); +static_assert(length(123) >= length(123000)); +static_assert(length(321) >= length(123000)); +static_assert(!(length(321) < length(123000))); +static_assert(!(length(123) < length(123000))); +static_assert(!(length(321) <= length(123000))); +static_assert(!(length(123) > length(321000))); +static_assert(!(length(123) > length(123000))); +static_assert(!(length(123) >= length(321000))); + +// dimensionless + +static_assert(quantity{123} < 321); +static_assert(quantity{123} <= 123); +static_assert(quantity{123} <= 321); +static_assert(quantity{321} > 123); +static_assert(quantity{123} >= 123); +static_assert(quantity{321} >= 123); + +static_assert(123 < quantity{321}); +static_assert(123 <= quantity{123}); +static_assert(123 <= quantity{321}); +static_assert(321 > quantity{123}); +static_assert(123 >= quantity{123}); +static_assert(321 >= quantity{123}); + + +////////////////// +// dimensionless +////////////////// + static_assert(std::equality_comparable_with, int>); static_assert(std::equality_comparable_with, double>); static_assert(std::equality_comparable_with, int>); static_assert(!std::equality_comparable_with, double>); -// quantity_cast - -static_assert(compare>(2_q_km))::unit, metre>); - -static_assert(quantity_cast>(2_q_km).count() == 2000); -static_assert(quantity_cast>(2000_q_m).count() == 2); -static_assert(quantity_cast>(1.23_q_m).count() == 1); -static_assert(quantity_cast(2_q_km).count() == 2000); -static_assert(quantity_cast(2000_q_m).count() == 2); -static_assert(quantity_cast(1.23_q_m).count() == 1); -static_assert(quantity_cast(2000.0_q_m / 3600.0_q_s).count() == 2); - -// dimensionless - -static_assert(std::is_convertible_v>); -static_assert(std::is_convertible_v>); -static_assert(!std::is_convertible_v>); -static_assert(std::is_convertible_v>); - -static_assert(!std::is_convertible_v>>); -static_assert(std::is_constructible_v>, double>); - -static_assert(dimensionless(1.23) + dimensionless(1.23) == dimensionless(2.46)); -static_assert(dimensionless(1.23) + dimensionless(1.23) == 2.46); -static_assert(dimensionless(1.23) + 1.23 == 2.46); -static_assert(1.23 + dimensionless(1.23) == 2.46); -static_assert(dimensionless(1) + 1 == 2); -static_assert(dimensionless(1) + 1 == 2); - template -concept invalid_dimensionless_operations = requires -{ +concept invalid_dimensionless_operations = requires { requires !requires(dimensionless d) { d + 1.23; }; requires !requires(dimensionless d) { 1.23 + d; }; - requires !requires(dimensionless, Int> d) { 1 + d; }; - requires !requires(dimensionless, Int> d) { d + 1; }; + requires !requires(dimensionless d) { 1 + d; }; + requires !requires(dimensionless d) { d + 1; }; }; static_assert(invalid_dimensionless_operations); @@ -319,36 +654,36 @@ static_assert(50._q_m / 100._q_m == dimensionless(50)); static_assert(dimensionless(dimensionless(50)).count() == 0.5); -static_assert(std::is_same_v>); -static_assert(std::is_same_v>); -// time +//////////////// +// alias units +//////////////// -static_assert(1_q_h == 3600_q_s); +static_assert(compare>); +static_assert(2_q_l + 2_q_ml == 2002_q_cm3); +static_assert(2_q_l + 2_q_ml == 2002_q_ml); +static_assert(2_q_l + 2_q_cm3 == 2002_q_ml); +static_assert(2_q_dm3 + 2_q_cm3 == 2002_q_ml); -template -concept no_crossdimensional_equality = !requires { 1_q_s == length(1); }; -static_assert(no_crossdimensional_equality); +////////////////// +// quantity_cast +////////////////// -// length +static_assert(compare>(2_q_km))::unit, metre>); -static_assert(1_q_km == 1000_q_m); -static_assert(1_q_km + 1_q_m == 1001_q_m); -static_assert(10_q_km / 5_q_km == 2); -static_assert(10_q_km / 2 == 5_q_km); +static_assert(quantity_cast>(2_q_km).count() == 2000); +static_assert(quantity_cast>(2000_q_m).count() == 2); +static_assert(quantity_cast>(1.23_q_m).count() == 1); +static_assert(quantity_cast(2_q_km).count() == 2000); +static_assert(quantity_cast(2000_q_m).count() == 2); +static_assert(quantity_cast(1.23_q_m).count() == 1); +static_assert(quantity_cast(2000.0_q_m / 3600.0_q_s).count() == 2); -// speed - -static_assert(10_q_m / 5_q_s == 2_q_m_per_s); -static_assert(10 / 5_q_s * 1_q_m == 2_q_m_per_s); -static_assert(1_q_km / 1_q_s == 1000_q_m_per_s); -static_assert(2_q_km_per_h * 2_q_h == 4_q_km); -static_assert(2_q_km / 2_q_km_per_h == 1_q_h); - -static_assert(compare(2_q_m)), decltype(4_q_m2)>); +//////////////// // downcasting +//////////////// #if UNITS_DOWNCAST_MODE == 0 diff --git a/test/unit_test/static/si_test.cpp b/test/unit_test/static/si_test.cpp index c0690e89..4966ee36 100644 --- a/test/unit_test/static/si_test.cpp +++ b/test/unit_test/static/si_test.cpp @@ -20,8 +20,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include "test_tools.h" +#include #include -#include namespace {