Upcasting facility refactored by adding additional alias templates

This commit is contained in:
Mateusz Pusz
2019-04-09 16:53:34 +02:00
parent 373e70f2b1
commit fe158440bb
8 changed files with 69 additions and 52 deletions

View File

@@ -54,8 +54,7 @@ derived from `units::dimension` class template:
template<typename T> template<typename T>
concept Dimension = concept Dimension =
std::is_empty_v<T> && std::is_empty_v<T> &&
detail::is_dimension<typename T::base_type> && // exposition only detail::is_dimension<upcast_from<T>>; // exposition only
DerivedFrom<T, typename T::base_type>;
``` ```
#### `Exponents` #### `Exponents`
@@ -199,8 +198,7 @@ derived from `units::unit` class template:
template<typename T> template<typename T>
concept Unit = concept Unit =
std::is_empty_v<T> && std::is_empty_v<T> &&
detail::is_unit<typename T::base_type> && // exposition only detail::is_unit<upcast_from<T>>; // exposition only
DerivedFrom<T, typename T::base_type>;
``` ```
### `Quantities` ### `Quantities`
@@ -344,31 +342,33 @@ and
are not arguably much easier to understand thus provide better user experience. 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 Upcasting capability is provided through dedicated `upcasting_traits`, a few helper aliases and by
type in `upcast_base` class template. `base_type` member type in `upcast_base` class template.
```cpp ```cpp
template<Upcastable T>
using upcast_from = typename T::base_type;
template<typename T> template<typename T>
struct upcasting_traits : std::type_identity<T> {}; using upcast_to = std::type_identity<T>;
template<typename T>
struct upcasting_traits : upcast_to<T> {};
template<typename T> template<typename T>
using upcasting_traits_t = typename upcasting_traits<T>::type; using upcasting_traits_t = typename upcasting_traits<T>::type;
``` ```
With that the upcasting functionality is enabled by:
```cpp ```cpp
struct dimension_length : make_dimension_t<exp<base_dim_length, 1>> {}; struct dimension_length : make_dimension_t<exp<base_dim_length, 1>> {};
template<> struct upcasting_traits<upcast_from<dimension_length>> : upcast_to<dimension_length> {};
template<>
struct upcasting_traits<typename dimension_length::base_type> :
std::type_identity<dimension_length> {};
``` ```
```cpp ```cpp
struct kilometer : unit<dimension_length, std::kilo> {}; struct kilometer : unit<dimension_length, std::kilo> {};
template<> struct upcasting_traits<upcast_from<kilometer>> : upcast_to<kilometer> {};
template<>
struct upcasting_traits<typename kilometer::base_type> :
std::type_identity<kilometer> {};
``` ```
@@ -379,14 +379,14 @@ In order to extend the library with custom dimensions the user has to:
```cpp ```cpp
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
template<> struct upcasting_traits<typename dimension_velocity::base_type> : std::type_identity<dimension_velocity> {}; template<> struct upcasting_traits<upcast_from<dimension_velocity>> : upcast_to<dimension_velocity> {};
``` ```
2. Define the base unit (`std::ratio<1>`) and secondary ones and provide upcasting traits for them via: 2. Define the base unit (`std::ratio<1>`) and secondary ones and provide upcasting traits for them via:
```cpp ```cpp
struct meter_per_second : unit<dimension_velocity, std::ratio<1>> {}; struct meter_per_second : unit<dimension_velocity, std::ratio<1>> {};
template<> struct upcasting_traits<typename meter_per_second::base_type> : std::type_identity<meter_per_second> {}; template<> struct upcasting_traits<upcast_from<meter_per_second>> : upcast_to<meter_per_second> {};
``` ```
3. Define a concept that will match a new dimension: 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`, 18. Should we standardize accompany tools (`type_list` operations, `static_sign`, `static_abs`,
`static_gcd`, `common_ratio`)? `static_gcd`, `common_ratio`)?
19. Do we need to support fractional exponents (i.e. `dimension<exp<"length", 2, 3>>` as 2/3)?
20. implicit conversion of quantity<Unit,Y> to quantity<Unit,Z> is allowed if Y and Z are implicitly convertible.
assignment between quantity<Unit,Y> and quantity<Unit,Z> is allowed if Y and Z are implicitly convertible.
21. explicit conversion between quantity<Unit1,Y> and quantity<Unit2,Z> is allowed if Unit1 and Unit2 have the same dimensions and if Y and Z are implicitly convertible.
implicit conversion between quantity<Unit1,Y> and quantity<Unit2,Z> is allowed if Unit1 reduces to exactly the same combination of base units as Unit2 and if Y and Z are convertible.

View File

@@ -110,20 +110,30 @@ namespace units {
template<Ratio Ratio1, Ratio Ratio2> template<Ratio Ratio1, Ratio Ratio2>
using common_ratio_t = typename common_ratio<Ratio1, Ratio2>::type; using common_ratio_t = typename common_ratio<Ratio1, Ratio2>::type;
// upcast_base // upcasting
template<typename BaseType> template<typename BaseType>
struct upcast_base { struct upcast_base {
using base_type = BaseType; using base_type = BaseType;
}; };
// upcasting_traits template<typename T>
concept bool Upcastable =
requires {
typename T::base_type;
} &&
std::experimental::ranges::DerivedFrom<T, upcast_base<typename T::base_type>>;
template<Upcastable T>
using upcast_from = typename T::base_type;
template<typename T> template<typename T>
struct upcasting_traits : std::type_identity<T> {}; using upcast_to = std::type_identity<T>;
template<typename T>
struct upcasting_traits : upcast_to<T> {};
template<typename T> template<typename T>
using upcasting_traits_t = typename upcasting_traits<T>::type; using upcasting_traits_t = typename upcasting_traits<T>::type;
} // namespace units } // namespace units

View File

@@ -101,8 +101,7 @@ namespace units {
template<typename T> template<typename T>
concept bool Dimension = concept bool Dimension =
std::is_empty_v<T> && std::is_empty_v<T> &&
detail::is_dimension<typename T::base_type> && detail::is_dimension<upcast_from<T>>;
std::experimental::ranges::DerivedFrom<T, typename T::base_type>;
// dim_invert // dim_invert

View File

@@ -28,25 +28,25 @@
namespace units { namespace units {
struct dimension_frequency : make_dimension_t<exp<base_dim_time, -1>> {}; struct dimension_frequency : make_dimension_t<exp<base_dim_time, -1>> {};
template<> struct upcasting_traits<typename dimension_frequency::base_type> : std::type_identity<dimension_frequency> {}; template<> struct upcasting_traits<upcast_from<dimension_frequency>> : upcast_to<dimension_frequency> {};
struct millihertz : unit<dimension_frequency, std::milli> {}; struct millihertz : unit<dimension_frequency, std::milli> {};
template<> struct upcasting_traits<typename millihertz::base_type> : std::type_identity<millihertz> {}; template<> struct upcasting_traits<upcast_from<millihertz>> : upcast_to<millihertz> {};
struct hertz : unit<dimension_frequency, std::ratio<1>> {}; struct hertz : unit<dimension_frequency, std::ratio<1>> {};
template<> struct upcasting_traits<typename hertz::base_type> : std::type_identity<hertz> {}; template<> struct upcasting_traits<upcast_from<hertz>> : upcast_to<hertz> {};
struct kilohertz : unit<dimension_frequency, std::kilo> {}; struct kilohertz : unit<dimension_frequency, std::kilo> {};
template<> struct upcasting_traits<typename kilohertz::base_type> : std::type_identity<kilohertz> {}; template<> struct upcasting_traits<upcast_from<kilohertz>> : upcast_to<kilohertz> {};
struct megahertz : unit<dimension_frequency, std::mega> {}; struct megahertz : unit<dimension_frequency, std::mega> {};
template<> struct upcasting_traits<typename megahertz::base_type> : std::type_identity<megahertz> {}; template<> struct upcasting_traits<upcast_from<megahertz>> : upcast_to<megahertz> {};
struct gigahertz : unit<dimension_frequency, std::giga> {}; struct gigahertz : unit<dimension_frequency, std::giga> {};
template<> struct upcasting_traits<typename gigahertz::base_type> : std::type_identity<gigahertz> {}; template<> struct upcasting_traits<upcast_from<gigahertz>> : upcast_to<gigahertz> {};
struct terahertz : unit<dimension_frequency, std::tera> {}; struct terahertz : unit<dimension_frequency, std::tera> {};
template<> struct upcasting_traits<typename terahertz::base_type> : std::type_identity<terahertz> {}; template<> struct upcasting_traits<upcast_from<terahertz>> : upcast_to<terahertz> {};
template<Unit U = hertz, Number Rep = double> template<Unit U = hertz, Number Rep = double>
using frequency = quantity<dimension_frequency, U, Rep>; using frequency = quantity<dimension_frequency, U, Rep>;

View File

@@ -29,33 +29,33 @@ namespace units {
// dimension // dimension
struct dimension_length : make_dimension_t<exp<base_dim_length, 1>> {}; struct dimension_length : make_dimension_t<exp<base_dim_length, 1>> {};
template<> struct upcasting_traits<typename dimension_length::base_type> : std::type_identity<dimension_length> {}; template<> struct upcasting_traits<upcast_from<dimension_length>> : upcast_to<dimension_length> {};
// SI units // SI units
struct millimeter : unit<dimension_length, std::milli> {}; struct millimeter : unit<dimension_length, std::milli> {};
template<> struct upcasting_traits<typename millimeter::base_type> : std::type_identity<millimeter> {}; template<> struct upcasting_traits<upcast_from<millimeter>> : upcast_to<millimeter> {};
struct centimeter : unit<dimension_length, std::ratio<1, 100>> {}; struct centimeter : unit<dimension_length, std::ratio<1, 100>> {};
template<> struct upcasting_traits<typename centimeter::base_type> : std::type_identity<centimeter> {}; template<> struct upcasting_traits<upcast_from<centimeter>> : upcast_to<centimeter> {};
struct meter : unit<dimension_length, std::ratio<1>> {}; struct meter : unit<dimension_length, std::ratio<1>> {};
template<> struct upcasting_traits<typename meter::base_type> : std::type_identity<meter> {}; template<> struct upcasting_traits<upcast_from<meter>> : upcast_to<meter> {};
struct kilometer : unit<dimension_length, std::kilo> {}; struct kilometer : unit<dimension_length, std::kilo> {};
template<> struct upcasting_traits<typename kilometer::base_type> : std::type_identity<kilometer> {}; template<> struct upcasting_traits<upcast_from<kilometer>> : upcast_to<kilometer> {};
// US customary units // US customary units
struct yard : unit<dimension_length, std::ratio<9'144, 10'000>> {}; struct yard : unit<dimension_length, std::ratio<9'144, 10'000>> {};
template<> struct upcasting_traits<typename yard::base_type> : std::type_identity<yard> {}; template<> struct upcasting_traits<upcast_from<yard>> : upcast_to<yard> {};
struct foot : unit<dimension_length, std::ratio_multiply<std::ratio<1, 3>, yard::ratio>> {}; struct foot : unit<dimension_length, std::ratio_multiply<std::ratio<1, 3>, yard::ratio>> {};
template<> struct upcasting_traits<typename foot::base_type> : std::type_identity<foot> {}; template<> struct upcasting_traits<upcast_from<foot>> : upcast_to<foot> {};
struct inch : unit<dimension_length, std::ratio_multiply<std::ratio<1, 12>, foot::ratio>> {}; struct inch : unit<dimension_length, std::ratio_multiply<std::ratio<1, 12>, foot::ratio>> {};
template<> struct upcasting_traits<typename inch::base_type> : std::type_identity<inch> {}; template<> struct upcasting_traits<upcast_from<inch>> : upcast_to<inch> {};
struct mile : unit<dimension_length, std::ratio_multiply<std::ratio<1'760>, yard::ratio>> {}; struct mile : unit<dimension_length, std::ratio_multiply<std::ratio<1'760>, yard::ratio>> {};
template<> struct upcasting_traits<typename mile::base_type> : std::type_identity<mile> {}; template<> struct upcasting_traits<upcast_from<mile>> : upcast_to<mile> {};
// length // length
template<Unit U = meter, Number Rep = double> template<Unit U = meter, Number Rep = double>

View File

@@ -28,25 +28,25 @@
namespace units { namespace units {
struct dimension_time : make_dimension_t<exp<base_dim_time, 1>> {}; struct dimension_time : make_dimension_t<exp<base_dim_time, 1>> {};
template<> struct upcasting_traits<typename dimension_time::base_type> : std::type_identity<dimension_time> {}; template<> struct upcasting_traits<upcast_from<dimension_time>> : upcast_to<dimension_time> {};
struct nanosecond : unit<dimension_time, std::nano> {}; struct nanosecond : unit<dimension_time, std::nano> {};
template<> struct upcasting_traits<typename nanosecond::base_type> : std::type_identity<nanosecond> {}; template<> struct upcasting_traits<upcast_from<nanosecond>> : upcast_to<nanosecond> {};
struct microsecond : unit<dimension_time, std::micro> {}; struct microsecond : unit<dimension_time, std::micro> {};
template<> struct upcasting_traits<typename microsecond::base_type> : std::type_identity<microsecond> {}; template<> struct upcasting_traits<upcast_from<microsecond>> : upcast_to<microsecond> {};
struct millisecond : unit<dimension_time, std::milli> {}; struct millisecond : unit<dimension_time, std::milli> {};
template<> struct upcasting_traits<typename millisecond::base_type> : std::type_identity<millisecond> {}; template<> struct upcasting_traits<upcast_from<millisecond>> : upcast_to<millisecond> {};
struct second : unit<dimension_time, std::ratio<1>> {}; struct second : unit<dimension_time, std::ratio<1>> {};
template<> struct upcasting_traits<typename second::base_type> : std::type_identity<second> {}; template<> struct upcasting_traits<upcast_from<second>> : upcast_to<second> {};
struct minute : unit<dimension_time, std::ratio<60>> {}; struct minute : unit<dimension_time, std::ratio<60>> {};
template<> struct upcasting_traits<typename minute::base_type> : std::type_identity<minute> {}; template<> struct upcasting_traits<upcast_from<minute>> : upcast_to<minute> {};
struct hour : unit<dimension_time, std::ratio<3600>> {}; struct hour : unit<dimension_time, std::ratio<3600>> {};
template<> struct upcasting_traits<typename hour::base_type> : std::type_identity<hour> {}; template<> struct upcasting_traits<upcast_from<hour>> : upcast_to<hour> {};
template<Unit U = second, Number Rep = double> template<Unit U = second, Number Rep = double>
using time = quantity<dimension_time, U, Rep>; using time = quantity<dimension_time, U, Rep>;

View File

@@ -29,16 +29,16 @@
namespace units { namespace units {
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
template<> struct upcasting_traits<typename dimension_velocity::base_type> : std::type_identity<dimension_velocity> {}; template<> struct upcasting_traits<upcast_from<dimension_velocity>> : upcast_to<dimension_velocity> {};
struct meter_per_second : unit<dimension_velocity, std::ratio<1>> {}; struct meter_per_second : unit<dimension_velocity, std::ratio<1>> {};
template<> struct upcasting_traits<typename meter_per_second::base_type> : std::type_identity<meter_per_second> {}; template<> struct upcasting_traits<upcast_from<meter_per_second>> : upcast_to<meter_per_second> {};
struct kilometer_per_hour : unit<dimension_velocity, std::ratio_divide<kilometer::ratio, hour::ratio>> {}; struct kilometer_per_hour : unit<dimension_velocity, std::ratio_divide<kilometer::ratio, hour::ratio>> {};
template<> struct upcasting_traits<typename kilometer_per_hour::base_type> : std::type_identity<kilometer_per_hour> {}; template<> struct upcasting_traits<upcast_from<kilometer_per_hour>> : upcast_to<kilometer_per_hour> {};
struct mile_per_hour : unit<dimension_velocity, std::ratio_divide<mile::ratio, hour::ratio>> {}; struct mile_per_hour : unit<dimension_velocity, std::ratio_divide<mile::ratio, hour::ratio>> {};
template<> struct upcasting_traits<typename mile_per_hour::base_type> : std::type_identity<mile_per_hour> {}; template<> struct upcasting_traits<upcast_from<mile_per_hour>> : upcast_to<mile_per_hour> {};
template<Unit U = meter_per_second, Number Rep = double> template<Unit U = meter_per_second, Number Rep = double>
using velocity = quantity<dimension_velocity, U, Rep>; using velocity = quantity<dimension_velocity, U, Rep>;

View File

@@ -49,7 +49,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Unit = concept bool Unit =
std::is_empty_v<T> && std::is_empty_v<T> &&
detail::is_unit<typename T::base_type> && detail::is_unit<upcast_from<T>>;
std::experimental::ranges::DerivedFrom<T, typename T::base_type>;
} // namespace units } // namespace units