diff --git a/doc/DESIGN.md b/doc/DESIGN.md index 51959d42..a016d618 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -54,8 +54,7 @@ derived from `units::dimension` class template: template concept Dimension = std::is_empty_v && - detail::is_dimension && // exposition only - DerivedFrom; + detail::is_dimension>; // exposition only ``` #### `Exponents` @@ -199,8 +198,7 @@ derived from `units::unit` class template: template concept Unit = std::is_empty_v && - detail::is_unit && // exposition only - DerivedFrom; + detail::is_unit>; // exposition only ``` ### `Quantities` @@ -344,31 +342,33 @@ and are not arguably much easier to understand thus provide better user experience. -Upcasting capability is provided through dedicated `upcasting_traits` and by `base_type` member -type in `upcast_base` class template. +Upcasting capability is provided through dedicated `upcasting_traits`, a few helper aliases and by +`base_type` member type in `upcast_base` class template. ```cpp +template +using upcast_from = typename T::base_type; + template -struct upcasting_traits : std::type_identity {}; +using upcast_to = std::type_identity; + +template +struct upcasting_traits : upcast_to {}; template using upcasting_traits_t = typename upcasting_traits::type; ``` +With that the upcasting functionality is enabled by: + ```cpp struct dimension_length : make_dimension_t> {}; - -template<> -struct upcasting_traits : - std::type_identity {}; +template<> struct upcasting_traits> : upcast_to {}; ``` ```cpp struct kilometer : unit {}; - -template<> -struct upcasting_traits : - std::type_identity {}; +template<> struct upcasting_traits> : upcast_to {}; ``` @@ -379,14 +379,14 @@ In order to extend the library with custom dimensions the user has to: ```cpp struct dimension_velocity : make_dimension_t, exp> {}; -template<> struct upcasting_traits : std::type_identity {}; +template<> struct upcasting_traits> : upcast_to {}; ``` 2. Define the base unit (`std::ratio<1>`) and secondary ones and provide upcasting traits for them via: ```cpp struct meter_per_second : unit> {}; -template<> struct upcasting_traits : std::type_identity {}; +template<> struct upcasting_traits> : upcast_to {}; ``` 3. Define a concept that will match a new dimension: @@ -528,3 +528,12 @@ Additionally, it should make the error logs even shorter thus easier to understa 18. Should we standardize accompany tools (`type_list` operations, `static_sign`, `static_abs`, `static_gcd`, `common_ratio`)? + +19. Do we need to support fractional exponents (i.e. `dimension>` as 2/3)? + +20. implicit conversion of quantity to quantity is allowed if Y and Z are implicitly convertible. + assignment between quantity and quantity is allowed if Y and Z are implicitly convertible. + +21. explicit conversion between quantity and quantity is allowed if Unit1 and Unit2 have the same dimensions and if Y and Z are implicitly convertible. + implicit conversion between quantity and quantity is allowed if Unit1 reduces to exactly the same combination of base units as Unit2 and if Y and Z are convertible. + diff --git a/src/include/units/bits/tools.h b/src/include/units/bits/tools.h index eaaa183d..c4b4edda 100644 --- a/src/include/units/bits/tools.h +++ b/src/include/units/bits/tools.h @@ -110,20 +110,30 @@ namespace units { template using common_ratio_t = typename common_ratio::type; - // upcast_base + // upcasting template struct upcast_base { using base_type = BaseType; }; - // upcasting_traits + template + concept bool Upcastable = + requires { + typename T::base_type; + } && + std::experimental::ranges::DerivedFrom>; + + template + using upcast_from = typename T::base_type; template - struct upcasting_traits : std::type_identity {}; + using upcast_to = std::type_identity; + + template + struct upcasting_traits : upcast_to {}; template using upcasting_traits_t = typename upcasting_traits::type; - } // namespace units diff --git a/src/include/units/dimension.h b/src/include/units/dimension.h index 152a25ad..29791b49 100644 --- a/src/include/units/dimension.h +++ b/src/include/units/dimension.h @@ -101,8 +101,7 @@ namespace units { template concept bool Dimension = std::is_empty_v && - detail::is_dimension && - std::experimental::ranges::DerivedFrom; + detail::is_dimension>; // dim_invert diff --git a/src/include/units/si/frequency.h b/src/include/units/si/frequency.h index 433f905f..d54f0ac8 100644 --- a/src/include/units/si/frequency.h +++ b/src/include/units/si/frequency.h @@ -28,25 +28,25 @@ namespace units { struct dimension_frequency : make_dimension_t> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct millihertz : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct hertz : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct kilohertz : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct megahertz : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct gigahertz : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct terahertz : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; template using frequency = quantity; diff --git a/src/include/units/si/length.h b/src/include/units/si/length.h index 2a6ae42f..9381110f 100644 --- a/src/include/units/si/length.h +++ b/src/include/units/si/length.h @@ -29,33 +29,33 @@ namespace units { // dimension struct dimension_length : make_dimension_t> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; // SI units struct millimeter : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct centimeter : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct meter : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct kilometer : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; // US customary units struct yard : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct foot : unit, yard::ratio>> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct inch : unit, foot::ratio>> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct mile : unit, yard::ratio>> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; // length template diff --git a/src/include/units/si/time.h b/src/include/units/si/time.h index 29605c05..3d412cd6 100644 --- a/src/include/units/si/time.h +++ b/src/include/units/si/time.h @@ -28,25 +28,25 @@ namespace units { struct dimension_time : make_dimension_t> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct nanosecond : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct microsecond : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct millisecond : unit {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct second : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct minute : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct hour : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; template using time = quantity; diff --git a/src/include/units/si/velocity.h b/src/include/units/si/velocity.h index 60137874..8233bc8e 100644 --- a/src/include/units/si/velocity.h +++ b/src/include/units/si/velocity.h @@ -29,16 +29,16 @@ namespace units { struct dimension_velocity : make_dimension_t, exp> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct meter_per_second : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct kilometer_per_hour : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; struct mile_per_hour : unit> {}; - template<> struct upcasting_traits : std::type_identity {}; + template<> struct upcasting_traits> : upcast_to {}; template using velocity = quantity; diff --git a/src/include/units/unit.h b/src/include/units/unit.h index 148e922e..628a28ab 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -49,7 +49,6 @@ namespace units { template concept bool Unit = std::is_empty_v && - detail::is_unit && - std::experimental::ranges::DerivedFrom; + detail::is_unit>; } // namespace units