From 2e1ce83024057b3938379116c0023f78ba0053cf Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 26 Sep 2019 22:30:57 +0200 Subject: [PATCH] Downcasting facility refactored so the user does not have to write the boilerplate code anymore --- README.md | 2 +- doc/DESIGN.md | 261 +++++++++++++----- src/include/units/bits/downcasting.h | 33 ++- src/include/units/dimension.h | 31 ++- src/include/units/dimensions/acceleration.h | 6 +- src/include/units/dimensions/area.h | 22 +- src/include/units/dimensions/capacitance.h | 6 +- src/include/units/dimensions/current.h | 6 +- .../units/dimensions/electric_charge.h | 6 +- src/include/units/dimensions/energy.h | 6 +- src/include/units/dimensions/force.h | 6 +- src/include/units/dimensions/frequency.h | 26 +- src/include/units/dimensions/length.h | 33 +-- .../units/dimensions/luminous_intensity.h | 6 +- src/include/units/dimensions/mass.h | 10 +- src/include/units/dimensions/power.h | 6 +- src/include/units/dimensions/pressure.h | 6 +- src/include/units/dimensions/substance.h | 6 +- src/include/units/dimensions/temperature.h | 6 +- src/include/units/dimensions/time.h | 26 +- src/include/units/dimensions/velocity.h | 14 +- src/include/units/dimensions/voltage.h | 6 +- src/include/units/dimensions/volume.h | 22 +- src/include/units/math.h | 4 +- src/include/units/quantity.h | 8 +- src/include/units/unit.h | 27 +- test/unit_test/test_custom_units.cpp | 28 +- test/unit_test/test_dimension.cpp | 28 +- 28 files changed, 348 insertions(+), 299 deletions(-) diff --git a/README.md b/README.md index e955a6b7..c5d1981f 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer. - Support for derived dimensions in `exp` added - Added `pow()` and `sqrt()` operations on quantities - `units` removed from a `std::experimental` namespace - - `downcasting_traits` renamed to `downcast_traits` and refactored helpers + - Downcasting facility refactored so the user does not have to write the boilerplate code anymore - 0.3.1 Sep 18, 2019 - cmcstl2 dependency changed to range-v3 0.9.1 diff --git a/doc/DESIGN.md b/doc/DESIGN.md index 51f9e67b..7be294c3 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -82,7 +82,7 @@ template struct dimension : downcast_base> {}; ``` -`units::Dimension` is a Concept that is satisfied by a type that is empty and publicly +`units::Dimension` is a concept that is satisfied by a type that is empty and publicly derived from `units::dimension` class template: ```cpp @@ -139,10 +139,9 @@ struct base_dim_current { static constexpr const char* value = "current"; }; struct base_dim_temperature { static constexpr const char* value = "temperature"; }; struct base_dim_substance { static constexpr const char* value = "substance"; }; struct base_dim_luminous_intensity { static constexpr const char* value = "luminous intensity"; }; -``` +``` - -#### `make_dimension` +#### `derived_dimension` Above design of dimensions is created with the ease of use for end users in mind. Compile-time errors should provide as short as possible template instantiations strings that should be easy to @@ -162,53 +161,52 @@ static_assert(v1 == v2); Above code, no matter what is the order of the base dimensions in an expression forming our result, must produce the same `Velocity` type so that both values can be easily compared. In order to achieve -that, `dimension` class templates should never be instantiated manually but through a `make_dimension_t` -template metaprogramming factory function: +that, `dimension` class templates should never be instantiated manually but through a `derived_dimension` +helper: ```cpp -template -struct make_dimension { - using type = /* unspecified */; -}; - -template -using make_dimension_t = make_dimension::type; +template +struct derived_dimension; ``` +`Child` class template parameter is a part of a CRTP idiom and is used to provide a downcasting facility +described later in this document. + So for example to create a `velocity` type we have to do: ```cpp -struct velocity : make_dimension_t, exp> {}; +struct velocity : derived_dimension, exp> {}; ``` -In order to make `make_dimension_t` work as expected it has to provide unique ordering for +In order to make `derived_dimension` work as expected it has to provide unique ordering for contained base dimensions. Beside providing ordering to base dimensions it also has to: - aggregate two arguments of the same base dimension but different exponents - eliminate two arguments of the same base dimension and with opposite equal exponents -`make_dimension_t` is also able to form a dimension type based not only on base dimensions but +`derived_dimension` is also able to form a dimension type based not only on base dimensions but it can take other derived dimensions as well. So for some more complex dimensions user can type either: ```cpp -struct pressure : make_dimension_t, exp, exp> {}; +struct pressure : derived_dimension, exp, exp> {}; ``` or ```cpp -struct pressure : make_dimension_t, exp> {}; +struct pressure : derived_dimension, exp> {}; ``` -In the second case `make_dimension_t` will extract all derived dimensions into the list of +In the second case `derived_dimension` will extract all derived dimensions into the list of exponents of base dimensions. Thanks to that both cases will result with exactly the same base -class formed only from the exponents of base units. +class formed only from the exponents of base units. #### `merge_dimension` -`units::merge_dimension` is similar to `make_dimension` but instead of sorting the whole list -of base dimensions from scratch it assumes that provided input `dimension` types are already -sorted as a result of `make_dimension`. +`units::merge_dimension` is a type alias that works similarly to `derived_dimension` but instead +of sorting the whole list of base dimensions from scratch it assumes that provided input `dimension` +types are already sorted as a result of `derived_dimension`. Also contrary to `derived_dimension` +it works only with exponents of bas dimensions (no derived dimensions allowed). Typical use case for `merge_dimension` is to produce final `dimension` return type of multiplying two different dimensions: @@ -226,15 +224,6 @@ template using dimension_multiply_t = dimension_multiply::type; ``` -Example implementation of `merge_dimension` may look like: - -```cpp -template -struct merge_dimension { - using type = detail::dim_consolidate_t>; -}; -``` - ### `Units` @@ -249,26 +238,69 @@ struct unit : downcast_base> { }; ``` +All units are created with a `derived_unit` helper: + +```cpp +template +struct derived_unit; +``` + For example to define the base unit of `length`: ```cpp -struct metre : unit {}; +struct metre : derived_unit {}; ``` -Also there are few alias templates provided as convenience helpers to simplify `Ratio` handling: -- units with prefixes +Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used +to provide downcasting facility (described below). + +`derived_unit` has a few partial useful specializations: +- helper to create a base unit of a specified dimension ```cpp -struct kilometre : kilo {}; +template +struct derived_unit; ``` -- derived units +```cpp +struct metre : derived_unit {}; +``` + +- helper to create other units for a specified dimension ```cpp -struct kilometre_per_hour : derived_unit {}; -``` +template +struct derived_unit; +``` -`units::Unit` is a Concept that is satisfied by a type that is empty and publicly +```cpp +struct yard : derived_unit> {}; +``` + +- helper to create a unit with a SI prefix + +```cpp +template +struct derived_unit; +``` + +```cpp +struct kilometre : derived_unit> {}; +``` + +- helper that automatically calculates ratio based on info in desired dimension and provided list + of units of base dimensions + +```cpp +template +struct derived_unit; +``` + +```cpp +struct kilometre_per_hour : derived_unit {}; +``` + +`units::Unit` is a concept that is satisfied by a type that is empty and publicly derived from `units::unit` class template: ```cpp @@ -284,11 +316,11 @@ concept Unit = expressed in a specific unit of that dimension: ```cpp -template +template class quantity; ``` -`units::Quantity` is a Concept that is satisfied by a type that is an instantiation of `units::quantity` +`units::Quantity` is a concept that is satisfied by a type that is an instantiation of `units::quantity` class template: ```cpp @@ -367,7 +399,7 @@ template constexpr quantity quantity_cast(const quantity& q); ``` -## Strong types instead of aliases, and type downcasting capability +## Strong types instead of aliases, and type downcasting facility Most of the important design decisions in the library are dictated by the requirement of providing the best user experience as possible. @@ -414,7 +446,7 @@ and starts to be really hard to analyze or debug. -That is why it was decided to provide automated downcasting capability when possible. With that the +That is why it was decided to provide automated downcasting capability when possible. Thanks to this feature the same code will result with such an error: ```text @@ -450,42 +482,126 @@ and are not arguably much easier to understand thus provide better user experience. -Downcasting capability is provided through dedicated `downcast_traits`, concept, a few helper aliases and by -`base_type` member type in `downcast_base` class template. +Downcasting facility provides a type substitution mechanism. It connects a specific primary template +class specialization with a strong type assigned to it by the user. A simplified mental model of the +facility may be represented as: + +```cpp +struct metre : unit>, std::ratio<1, 1, 0>>; +``` + +In the above example `metre` is a downcasting target (child class) and a specific `unit` class +template specialization is a downcasting source (base class). The downcasting facility provides +1 to 1 tpe substitution mechanism. Only one child class can be created for a specific base class +template instantiation. + +Downcasting facility is provided through 2 dedicated types, a concept, and a few helper template aliases. ```cpp template struct downcast_base { using base_type = BaseType; + friend auto downcast_guide(downcast_base); }; +``` +`units::downcast_base` is a class that implements CRTP idiom, marks the base of downcasting +facility with a `base_type` member type, and provides a declaration of downcasting ADL friendly +(Hidden Friend) entry point member function `downcast_guide` that here does not return any specific +type. This non-member function is going to be defined in a child class template `downcast_helper` +and will return a target type of the downcasting operation. + +```cpp template concept Downcastable = requires { typename T::base_type; } && std::derived_from>; +``` +`units::Downcastable` is a concepts that verifies if a type implements and can be used in a downcasting +facility. + +```cpp +template +struct downcast_helper : T { + friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); } +}; +``` + +`units::downcast_helper` is another CRTP class template that provides the implementation of a +non-member friend function of the `downcast_base` class template which defines the target +type of downcasting operation. It is used in the following way to define `dimension` and +`unit` types in the library: + +```cpp +template +struct derived_dimension : downcast_helper> {}; +``` + +```cpp +template +struct derived_unit : downcast_helper>> {}; +``` + +With such CRTP types the only thing the user has to do to register a new type to a downcasting +facility is to publicly derive from one of those CRTP types and provide its new child type as +the first template parameter of the CRTP type. + +```cpp +struct metre : derived_unit {}; +``` + +Above types are used to define base and target of a downcasting operation. To perform the actual +downcasting operation a dedicated template alias is provided: + +```cpp +template +using downcast_target = decltype(detail::downcast_target_impl()); +``` + +`units::downcast_target` is used to obtain the target type of the downcasting operation registered +for a given specialization in a base type. + +For example to determine a downcasted type of a quantity multiply operation the following can be done: + +```cpp +using dim = dimension_multiply_t; +using common_rep = decltype(lhs.count() * rhs.count()); +using ret = quantity>>, common_rep>; +``` + +`detail::downcast_target_impl` checks if downcasting target is registered for the specific base class. +If yes, it returns the registered type. Otherwise, it works like a regular identity type returning +a provided base class. + +```cpp +namespace detail { + + template + concept bool has_downcast = requires { + downcast_guide(std::declval>()); + }; + + template + constexpr auto downcast_target_impl() + { + if constexpr(has_downcast) + return decltype(downcast_guide(std::declval>()))(); + else + return T(); + } + +} +``` + +Additionally there is on more simple helper alias provided that is used in the internal +library implementation: + +```cpp template using downcast_base_t = T::base_type; - -template -struct downcast_traits : std::type_identity {}; - -template -using downcast_traits_t = downcast_traits::type; -``` - -With that the downcasting functionality is enabled by: - -```cpp -struct length : make_dimension_t> {}; -template<> struct downcast_traits> : std::type_identity {}; -``` - -```cpp -struct kilometre : unit {}; -template<> struct downcast_traits> : std::type_identity {}; ``` @@ -498,13 +614,11 @@ In order to extend the library with custom dimensions the user has to: inline constexpr units::base_dimension base_dim_digital_information{"digital information"}; ``` -2. Create a new dimension type with the recipe of how to construct it from base dimensions and provide - downcasting trait for it: +2. Create a new dimension type with the recipe of how to construct it from base dimensions and + register it for a downcasting facitlity: ```cpp - struct digital_information : units::make_dimension_t> {}; - template<> - struct units::downcast_traits> : units::std::type_identity_t {}; + struct digital_information : units::derived_dimension> {}; ``` 2. Define a concept that will match a new dimension: @@ -514,14 +628,11 @@ In order to extend the library with custom dimensions the user has to: concept DigitalInformation = units::QuantityOf; ``` -3. Define units and provide downcasting traits for them: +3. Define units and register them to a downcasting facility: ```cpp - struct bit : units::unit {}; - template<> struct units::downcast_traits> : units::std::type_identity_t {}; - - struct byte : units::unit> {}; - template<> struct units::downcast_traits> : units::std::type_identity_t {}; + struct bit : units::derived_unit {}; + struct byte : units::derived_unit> {}; ``` 4. Provide user-defined literals for the most important units: diff --git a/src/include/units/bits/downcasting.h b/src/include/units/bits/downcasting.h index 6950b9c0..aa7ef102 100644 --- a/src/include/units/bits/downcasting.h +++ b/src/include/units/bits/downcasting.h @@ -30,6 +30,7 @@ namespace units { template struct downcast_base { using base_type = BaseType; + friend auto downcast_guide(downcast_base); }; template @@ -39,13 +40,33 @@ namespace units { } && std::derived_from>; + template + struct downcast_helper : T { + friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); } + }; + + namespace detail { + + template + concept bool has_downcast = requires { + downcast_guide(std::declval>()); + }; + + template + constexpr auto downcast_target_impl() + { + if constexpr(has_downcast) + return decltype(downcast_guide(std::declval>()))(); + else + return T(); + } + + } + + template + using downcast_target = decltype(detail::downcast_target_impl()); + template using downcast_base_t = T::base_type; - template - struct downcast_traits : std::type_identity {}; - - template - using downcast_traits_t = downcast_traits::type; - } // namespace units diff --git a/src/include/units/dimension.h b/src/include/units/dimension.h index 87ea5c2e..133cb65c 100644 --- a/src/include/units/dimension.h +++ b/src/include/units/dimension.h @@ -156,13 +156,11 @@ namespace units { struct dim_invert; template - struct dim_invert> : std::type_identity...>>> {}; + struct dim_invert> : std::type_identity...>>> {}; template using dim_invert_t = dim_invert>::type; - - // todo: force as the only user interface to create dimensions through modules // make_dimension namespace detail { @@ -224,15 +222,22 @@ namespace units { using type = extract_t, Num, Den>, ERest...>; }; + template + struct make_dimension { + using type = detail::dim_consolidate_t, exp_less>>; + }; + + template + using make_dimension_t = make_dimension::type; + } // namespace detail - template - struct make_dimension { - using type = detail::dim_consolidate_t, exp_less>>; - }; + // derived_dimension - template - using make_dimension_t = make_dimension::type; + template + struct derived_dimension : downcast_helper> {}; + + // merge_dimension template struct merge_dimension { @@ -248,7 +253,7 @@ namespace units { struct dimension_multiply; template - struct dimension_multiply, dimension> : std::type_identity, dimension>>> {}; + struct dimension_multiply, dimension> : std::type_identity, dimension>>> {}; template using dimension_multiply_t = dimension_multiply::type; @@ -267,21 +272,23 @@ namespace units { using dimension_divide_t = dimension_divide::type; // dimension_sqrt + template struct dimension_sqrt; template - struct dimension_sqrt> : std::type_identity...>>> {}; + struct dimension_sqrt> : std::type_identity...>>> {}; template using dimension_sqrt_t = dimension_sqrt::type; // dimension_pow + template struct dimension_pow; template - struct dimension_pow, N> : std::type_identity...>>> {}; + struct dimension_pow, N> : std::type_identity...>>> {}; template using dimension_pow_t = dimension_pow::type; diff --git a/src/include/units/dimensions/acceleration.h b/src/include/units/dimensions/acceleration.h index e7088e82..a57754dd 100644 --- a/src/include/units/dimensions/acceleration.h +++ b/src/include/units/dimensions/acceleration.h @@ -26,14 +26,12 @@ namespace units { - struct acceleration : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct acceleration : derived_dimension, exp> {}; template concept bool Acceleration = QuantityOf; - struct metre_per_second_sq : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct metre_per_second_sq : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/area.h b/src/include/units/dimensions/area.h index 66e725f8..b4806ffa 100644 --- a/src/include/units/dimensions/area.h +++ b/src/include/units/dimensions/area.h @@ -26,26 +26,16 @@ namespace units { - struct area : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct area : derived_dimension> {}; template concept bool Area = QuantityOf; - struct square_millimetre : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct square_centimetre : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct square_metre : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct square_kilometre : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct square_foot : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct square_millimetre : derived_unit {}; + struct square_centimetre : derived_unit {}; + struct square_metre : derived_unit {}; + struct square_kilometre : derived_unit {}; + struct square_foot : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/capacitance.h b/src/include/units/dimensions/capacitance.h index 5766f943..915c8cc9 100644 --- a/src/include/units/dimensions/capacitance.h +++ b/src/include/units/dimensions/capacitance.h @@ -28,14 +28,12 @@ namespace units { - struct capacitance : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct capacitance : derived_dimension, exp> {}; template concept bool Capacitance = QuantityOf; - struct farad : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct farad : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/current.h b/src/include/units/dimensions/current.h index e1cabe7e..13c92f2d 100644 --- a/src/include/units/dimensions/current.h +++ b/src/include/units/dimensions/current.h @@ -27,14 +27,12 @@ namespace units { - struct current : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct current : derived_dimension> {}; template concept bool Current = QuantityOf; - struct ampere : unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct ampere : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/electric_charge.h b/src/include/units/dimensions/electric_charge.h index 572f06a2..0f9dd99b 100644 --- a/src/include/units/dimensions/electric_charge.h +++ b/src/include/units/dimensions/electric_charge.h @@ -28,14 +28,12 @@ namespace units { - struct electric_charge : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct electric_charge : derived_dimension, exp> {}; template concept bool ElectricCharge = QuantityOf; - struct coulomb : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct coulomb : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/energy.h b/src/include/units/dimensions/energy.h index d6d5b1cd..5d568f83 100644 --- a/src/include/units/dimensions/energy.h +++ b/src/include/units/dimensions/energy.h @@ -28,14 +28,12 @@ namespace units { - struct energy : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct energy : derived_dimension, exp> {}; template concept bool Energy = QuantityOf; - struct joule : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct joule : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/force.h b/src/include/units/dimensions/force.h index 05bfef14..73f83136 100644 --- a/src/include/units/dimensions/force.h +++ b/src/include/units/dimensions/force.h @@ -28,14 +28,12 @@ namespace units { - struct force : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct force : derived_dimension, exp> {}; template concept bool Force = QuantityOf; - struct newton : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct newton : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/frequency.h b/src/include/units/dimensions/frequency.h index 5606e815..3c605cc8 100644 --- a/src/include/units/dimensions/frequency.h +++ b/src/include/units/dimensions/frequency.h @@ -27,29 +27,17 @@ namespace units { - struct frequency : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct frequency : derived_dimension> {}; template concept bool Frequency = QuantityOf; - struct hertz : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct millihertz : milli {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct kilohertz : kilo {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct megahertz : mega {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct gigahertz : giga {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct terahertz : tera {}; - template<> struct downcast_traits> : std::type_identity {}; + struct hertz : derived_unit {}; + struct millihertz : derived_unit> {}; + struct kilohertz : derived_unit> {}; + struct megahertz : derived_unit> {}; + struct gigahertz : derived_unit> {}; + struct terahertz : derived_unit> {}; inline namespace literals { diff --git a/src/include/units/dimensions/length.h b/src/include/units/dimensions/length.h index ef736c58..6061247c 100644 --- a/src/include/units/dimensions/length.h +++ b/src/include/units/dimensions/length.h @@ -27,24 +27,16 @@ namespace units { - struct length : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct length : derived_dimension> {}; template concept bool Length = QuantityOf; // SI units - struct metre : unit {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct millimetre : milli {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct centimetre : centi {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct kilometre : kilo {}; - template<> struct downcast_traits> : std::type_identity {}; + struct metre : derived_unit {}; + struct millimetre : derived_unit> {}; + struct centimetre : derived_unit> {}; + struct kilometre : derived_unit> {}; inline namespace literals { @@ -67,17 +59,10 @@ namespace units { } // namespace literals // US customary units - struct yard : unit> {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct foot : unit, yard::ratio>> {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct inch : unit, foot::ratio>> {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct mile : unit, yard::ratio>> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct yard : derived_unit> {}; + struct foot : derived_unit, yard::ratio>> {}; + struct inch : derived_unit, foot::ratio>> {}; + struct mile : derived_unit, yard::ratio>> {}; inline namespace literals { diff --git a/src/include/units/dimensions/luminous_intensity.h b/src/include/units/dimensions/luminous_intensity.h index fdd43594..0aef47d5 100644 --- a/src/include/units/dimensions/luminous_intensity.h +++ b/src/include/units/dimensions/luminous_intensity.h @@ -27,14 +27,12 @@ namespace units { - struct luminous_intensity : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct luminous_intensity : derived_dimension> {}; template concept bool LuminousIntensity = QuantityOf; - struct candela : unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct candela : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/mass.h b/src/include/units/dimensions/mass.h index 4533b0c6..fba5649c 100644 --- a/src/include/units/dimensions/mass.h +++ b/src/include/units/dimensions/mass.h @@ -27,17 +27,13 @@ namespace units { - struct mass : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct mass : derived_dimension> {}; template concept bool Mass = QuantityOf; - struct gram : unit> {}; - template<> struct downcast_traits> : std::type_identity {}; - - struct kilogram : kilo {}; - template<> struct downcast_traits> : std::type_identity {}; + struct gram : derived_unit> {}; + struct kilogram : derived_unit> {}; inline namespace literals { diff --git a/src/include/units/dimensions/power.h b/src/include/units/dimensions/power.h index de8a7492..e6d8964c 100644 --- a/src/include/units/dimensions/power.h +++ b/src/include/units/dimensions/power.h @@ -27,14 +27,12 @@ namespace units { - struct power : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct power : derived_dimension, exp> {}; template concept bool Power = QuantityOf; - struct watt : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct watt : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/pressure.h b/src/include/units/dimensions/pressure.h index f8eaa576..1698589d 100644 --- a/src/include/units/dimensions/pressure.h +++ b/src/include/units/dimensions/pressure.h @@ -28,14 +28,12 @@ namespace units { - struct pressure : make_dimension_t, exp> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct pressure : derived_dimension, exp> {}; template concept bool Pressure = QuantityOf; - struct pascal : derived_unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct pascal : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/substance.h b/src/include/units/dimensions/substance.h index 2cc21957..332a00f3 100644 --- a/src/include/units/dimensions/substance.h +++ b/src/include/units/dimensions/substance.h @@ -27,14 +27,12 @@ namespace units { - struct substance : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct substance : derived_dimension> {}; template concept bool Substance = QuantityOf; - struct mole : unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct mole : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/temperature.h b/src/include/units/dimensions/temperature.h index 90f3d06b..d2c69c1d 100644 --- a/src/include/units/dimensions/temperature.h +++ b/src/include/units/dimensions/temperature.h @@ -27,14 +27,12 @@ namespace units { - struct temperature : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity {}; + struct temperature : derived_dimension> {}; template concept bool ThermodynamicTemperature = QuantityOf; - struct kelvin : unit {}; - template<> struct downcast_traits> : std::type_identity {}; + struct kelvin : derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/time.h b/src/include/units/dimensions/time.h index 6cd5fb0c..0ec84970 100644 --- a/src/include/units/dimensions/time.h +++ b/src/include/units/dimensions/time.h @@ -27,29 +27,17 @@ namespace units { - struct time : make_dimension_t> {}; - template<> struct downcast_traits> : std::type_identity