Downcasting facility refactored so the user does not have to write the boilerplate code anymore

This commit is contained in:
Mateusz Pusz
2019-09-26 22:30:57 +02:00
parent ad69f338b8
commit 2e1ce83024
28 changed files with 348 additions and 299 deletions

View File

@@ -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 - Support for derived dimensions in `exp` added
- Added `pow()` and `sqrt()` operations on quantities - Added `pow()` and `sqrt()` operations on quantities
- `units` removed from a `std::experimental` namespace - `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 - 0.3.1 Sep 18, 2019
- cmcstl2 dependency changed to range-v3 0.9.1 - cmcstl2 dependency changed to range-v3 0.9.1

View File

@@ -82,7 +82,7 @@ template<Exponent... Es>
struct dimension : downcast_base<dimension<Es...>> {}; struct dimension : downcast_base<dimension<Es...>> {};
``` ```
`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: derived from `units::dimension` class template:
```cpp ```cpp
@@ -141,8 +141,7 @@ struct base_dim_substance { static constexpr const char* value = "substance"; };
struct base_dim_luminous_intensity { static constexpr const char* value = "luminous intensity"; }; struct base_dim_luminous_intensity { static constexpr const char* value = "luminous intensity"; };
``` ```
#### `derived_dimension`
#### `make_dimension`
Above design of dimensions is created with the ease of use for end users in mind. Compile-time 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 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, 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 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` that, `dimension` class templates should never be instantiated manually but through a `derived_dimension`
template metaprogramming factory function: helper:
```cpp ```cpp
template<Exponent... Es> template<typename Child, Exponent... Es>
struct make_dimension { struct derived_dimension;
using type = /* unspecified */;
};
template<Exponent... Es>
using make_dimension_t = make_dimension<Es...>::type;
``` ```
`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: So for example to create a `velocity` type we have to do:
```cpp ```cpp
struct velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; struct velocity : derived_dimension<velocity, exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
``` ```
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: contained base dimensions. Beside providing ordering to base dimensions it also has to:
- aggregate two arguments of the same base dimension but different exponents - aggregate two arguments of the same base dimension but different exponents
- eliminate two arguments of the same base dimension and with opposite equal 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 it can take other derived dimensions as well. So for some more complex dimensions user can
type either: type either:
```cpp ```cpp
struct pressure : make_dimension_t<exp<base_dim_mass, 1>, exp<base_dim_length, -1>, exp<base_dim_time, -2>> {}; struct pressure : derived_dimension<pressure, exp<base_dim_mass, 1>, exp<base_dim_length, -1>, exp<base_dim_time, -2>> {};
``` ```
or or
```cpp ```cpp
struct pressure : make_dimension_t<exp<force, 1>, exp<area, -1>> {}; struct pressure : derived_dimension<pressure, exp<force, 1>, exp<area, -1>> {};
``` ```
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 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` #### `merge_dimension`
`units::merge_dimension` is similar to `make_dimension` but instead of sorting the whole list `units::merge_dimension` is a type alias that works similarly to `derived_dimension` but instead
of base dimensions from scratch it assumes that provided input `dimension` types are already of sorting the whole list of base dimensions from scratch it assumes that provided input `dimension`
sorted as a result of `make_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 Typical use case for `merge_dimension` is to produce final `dimension` return type of multiplying
two different dimensions: two different dimensions:
@@ -226,15 +224,6 @@ template<Dimension D1, Dimension D2>
using dimension_multiply_t = dimension_multiply<typename D1::base_type, typename D2::base_type>::type; using dimension_multiply_t = dimension_multiply<typename D1::base_type, typename D2::base_type>::type;
``` ```
Example implementation of `merge_dimension` may look like:
```cpp
template<Dimension D1, Dimension D2>
struct merge_dimension {
using type = detail::dim_consolidate_t<mp::type_list_merge_sorted_t<D1, D2, exp_dim_id_less>>;
};
```
### `Units` ### `Units`
@@ -249,26 +238,69 @@ struct unit : downcast_base<unit<D, R>> {
}; };
``` ```
All units are created with a `derived_unit` helper:
```cpp
template<typename Child, typename...>
struct derived_unit;
```
For example to define the base unit of `length`: For example to define the base unit of `length`:
```cpp ```cpp
struct metre : unit<length> {}; struct metre : derived_unit<metre, length> {};
``` ```
Also there are few alias templates provided as convenience helpers to simplify `Ratio` handling: Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used
- units with prefixes 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 ```cpp
struct kilometre : kilo<metre> {}; template<typename Child, Dimension D>
struct derived_unit<Child, D>;
``` ```
- derived units
```cpp ```cpp
struct kilometre_per_hour : derived_unit<velocity, kilometre, hour> {}; struct metre : derived_unit<metre, length> {};
``` ```
`units::Unit` is a Concept that is satisfied by a type that is empty and publicly - helper to create other units for a specified dimension
```cpp
template<typename Child, Dimension D, Ratio R>
struct derived_unit<Child, D, R>;
```
```cpp
struct yard : derived_unit<yard, length, ratio<9'144, 10'000>> {};
```
- helper to create a unit with a SI prefix
```cpp
template<typename Child, Unit U>
struct derived_unit<Child, U>;
```
```cpp
struct kilometre : derived_unit<kilometre, kilo<metre>> {};
```
- helper that automatically calculates ratio based on info in desired dimension and provided list
of units of base dimensions
```cpp
template<typename Child, Dimension D, Unit U, Unit... Us>
struct derived_unit<Child, D, U, Us...>;
```
```cpp
struct kilometre_per_hour : derived_unit<kilometre_per_hour, velocity, kilometre, hour> {};
```
`units::Unit` is a concept that is satisfied by a type that is empty and publicly
derived from `units::unit` class template: derived from `units::unit` class template:
```cpp ```cpp
@@ -284,11 +316,11 @@ concept Unit =
expressed in a specific unit of that dimension: expressed in a specific unit of that dimension:
```cpp ```cpp
template<Unit U, Scalar Rep> template<Unit U, Scalar Rep = double>
class quantity; 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: class template:
```cpp ```cpp
@@ -367,7 +399,7 @@ template<Unit ToU, Scalar ToRep = double, typename U, typename Rep>
constexpr quantity<ToU, ToRep> quantity_cast(const quantity<U, Rep>& q); constexpr quantity<ToU, ToRep> quantity_cast(const quantity<U, Rep>& 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 Most of the important design decisions in the library are dictated by the requirement of providing
the best user experience as possible. the best user experience as possible.
@@ -414,7 +446,7 @@ and
starts to be really hard to analyze or debug. 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: same code will result with such an error:
```text ```text
@@ -450,42 +482,126 @@ 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.
Downcasting capability is provided through dedicated `downcast_traits`, concept, a few helper aliases and by Downcasting facility provides a type substitution mechanism. It connects a specific primary template
`base_type` member type in `downcast_base` class 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<dimension<exp<base_dim_length, 1>>, 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 ```cpp
template<typename BaseType> template<typename BaseType>
struct downcast_base { struct downcast_base {
using base_type = BaseType; 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<typename T> template<typename T>
concept Downcastable = concept Downcastable =
requires { requires {
typename T::base_type; typename T::base_type;
} && } &&
std::derived_from<T, downcast_base<typename T::base_type>>; std::derived_from<T, downcast_base<typename T::base_type>>;
```
`units::Downcastable` is a concepts that verifies if a type implements and can be used in a downcasting
facility.
```cpp
template<typename Target, Downcastable T>
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<typename Child, Exponent... Es>
struct derived_dimension : downcast_helper<Child, detail::make_dimension_t<Es...>> {};
```
```cpp
template<typename Child, Dimension D>
struct derived_unit<Child, D, R> : downcast_helper<Child, unit<D, ratio<1>>> {};
```
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<metre, length> {};
```
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<Downcastable T>
using downcast_target = decltype(detail::downcast_target_impl<T>());
```
`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<typename U1::dimension, typename U2::dimension>;
using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<downcast_target<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, 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<typename T>
concept bool has_downcast = requires {
downcast_guide(std::declval<downcast_base<T>>());
};
template<typename T>
constexpr auto downcast_target_impl()
{
if constexpr(has_downcast<T>)
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
else
return T();
}
}
```
Additionally there is on more simple helper alias provided that is used in the internal
library implementation:
```cpp
template<Downcastable T> template<Downcastable T>
using downcast_base_t = T::base_type; using downcast_base_t = T::base_type;
template<Downcastable T>
struct downcast_traits : std::type_identity<T> {};
template<Downcastable T>
using downcast_traits_t = downcast_traits<T>::type;
```
With that the downcasting functionality is enabled by:
```cpp
struct length : make_dimension_t<exp<base_dim_length, 1>> {};
template<> struct downcast_traits<downcast_base_t<length>> : std::type_identity<length> {};
```
```cpp
struct kilometre : unit<length, std::kilo> {};
template<> struct downcast_traits<downcast_base_t<kilometre>> : std::type_identity<kilometre> {};
``` ```
@@ -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"}; 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 2. Create a new dimension type with the recipe of how to construct it from base dimensions and
downcasting trait for it: register it for a downcasting facitlity:
```cpp ```cpp
struct digital_information : units::make_dimension_t<units::exp<base_dim_digital_information, 1>> {}; struct digital_information : units::derived_dimension<digital_information, units::exp<base_dim_digital_information, 1>> {};
template<>
struct units::downcast_traits<units::downcast_base_t<digital_information>> : units::std::type_identity_t<digital_information> {};
``` ```
2. Define a concept that will match a new 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<T, digital_information>; concept DigitalInformation = units::QuantityOf<T, digital_information>;
``` ```
3. Define units and provide downcasting traits for them: 3. Define units and register them to a downcasting facility:
```cpp ```cpp
struct bit : units::unit<digital_information> {}; struct bit : units::derived_unit<bit, digital_information> {};
template<> struct units::downcast_traits<units::downcast_base_t<bit>> : units::std::type_identity_t<bit> {}; struct byte : units::derived_unit<byte, digital_information, units::ratio<8>> {};
struct byte : units::unit<digital_information, units::ratio<8>> {};
template<> struct units::downcast_traits<units::downcast_base_t<byte>> : units::std::type_identity_t<byte> {};
``` ```
4. Provide user-defined literals for the most important units: 4. Provide user-defined literals for the most important units:

View File

@@ -30,6 +30,7 @@ namespace units {
template<typename BaseType> template<typename BaseType>
struct downcast_base { struct downcast_base {
using base_type = BaseType; using base_type = BaseType;
friend auto downcast_guide(downcast_base);
}; };
template<typename T> template<typename T>
@@ -39,13 +40,33 @@ namespace units {
} && } &&
std::derived_from<T, downcast_base<typename T::base_type>>; std::derived_from<T, downcast_base<typename T::base_type>>;
template<typename Target, Downcastable T>
struct downcast_helper : T {
friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); }
};
namespace detail {
template<typename T>
concept bool has_downcast = requires {
downcast_guide(std::declval<downcast_base<T>>());
};
template<typename T>
constexpr auto downcast_target_impl()
{
if constexpr(has_downcast<T>)
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
else
return T();
}
}
template<Downcastable T>
using downcast_target = decltype(detail::downcast_target_impl<T>());
template<Downcastable T> template<Downcastable T>
using downcast_base_t = T::base_type; using downcast_base_t = T::base_type;
template<Downcastable T>
struct downcast_traits : std::type_identity<T> {};
template<Downcastable T>
using downcast_traits_t = downcast_traits<T>::type;
} // namespace units } // namespace units

View File

@@ -156,13 +156,11 @@ namespace units {
struct dim_invert; struct dim_invert;
template<typename... Es> template<typename... Es>
struct dim_invert<dimension<Es...>> : std::type_identity<downcast_traits_t<dimension<exp_invert_t<Es>...>>> {}; struct dim_invert<dimension<Es...>> : std::type_identity<downcast_target<dimension<exp_invert_t<Es>...>>> {};
template<Dimension D> template<Dimension D>
using dim_invert_t = dim_invert<downcast_base_t<D>>::type; using dim_invert_t = dim_invert<downcast_base_t<D>>::type;
// todo: force as the only user interface to create dimensions through modules
// make_dimension // make_dimension
namespace detail { namespace detail {
@@ -224,8 +222,6 @@ namespace units {
using type = extract_t<exp<downcast_base_t<Dim>, Num, Den>, ERest...>; using type = extract_t<exp<downcast_base_t<Dim>, Num, Den>, ERest...>;
}; };
} // namespace detail
template<Exponent... Es> template<Exponent... Es>
struct make_dimension { struct make_dimension {
using type = detail::dim_consolidate_t<type_list_sort<detail::extract_t<Es...>, exp_less>>; using type = detail::dim_consolidate_t<type_list_sort<detail::extract_t<Es...>, exp_less>>;
@@ -234,6 +230,15 @@ namespace units {
template<Exponent... Es> template<Exponent... Es>
using make_dimension_t = make_dimension<Es...>::type; using make_dimension_t = make_dimension<Es...>::type;
} // namespace detail
// derived_dimension
template<typename Child, Exponent... Es>
struct derived_dimension : downcast_helper<Child, detail::make_dimension_t<Es...>> {};
// merge_dimension
template<Dimension D1, Dimension D2> template<Dimension D1, Dimension D2>
struct merge_dimension { struct merge_dimension {
using type = detail::dim_consolidate_t<type_list_merge_sorted<D1, D2, exp_less>>; using type = detail::dim_consolidate_t<type_list_merge_sorted<D1, D2, exp_less>>;
@@ -248,7 +253,7 @@ namespace units {
struct dimension_multiply; struct dimension_multiply;
template<typename... E1, typename... E2> template<typename... E1, typename... E2>
struct dimension_multiply<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast_traits_t<merge_dimension_t<dimension<E1...>, dimension<E2...>>>> {}; struct dimension_multiply<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast_target<merge_dimension_t<dimension<E1...>, dimension<E2...>>>> {};
template<Dimension D1, Dimension D2> template<Dimension D1, Dimension D2>
using dimension_multiply_t = dimension_multiply<typename D1::base_type, typename D2::base_type>::type; using dimension_multiply_t = dimension_multiply<typename D1::base_type, typename D2::base_type>::type;
@@ -267,21 +272,23 @@ namespace units {
using dimension_divide_t = dimension_divide<typename D1::base_type, typename D2::base_type>::type; using dimension_divide_t = dimension_divide<typename D1::base_type, typename D2::base_type>::type;
// dimension_sqrt // dimension_sqrt
template<Dimension D> template<Dimension D>
struct dimension_sqrt; struct dimension_sqrt;
template<typename... Es> template<typename... Es>
struct dimension_sqrt<dimension<Es...>> : std::type_identity<downcast_traits_t<dimension<exp_multiply_t<Es, 1, 2>...>>> {}; struct dimension_sqrt<dimension<Es...>> : std::type_identity<downcast_target<dimension<exp_multiply_t<Es, 1, 2>...>>> {};
template<Dimension D> template<Dimension D>
using dimension_sqrt_t = dimension_sqrt<typename D::base_type>::type; using dimension_sqrt_t = dimension_sqrt<typename D::base_type>::type;
// dimension_pow // dimension_pow
template<Dimension D, std::size_t N> template<Dimension D, std::size_t N>
struct dimension_pow; struct dimension_pow;
template<typename... Es, std::size_t N> template<typename... Es, std::size_t N>
struct dimension_pow<dimension<Es...>, N> : std::type_identity<downcast_traits_t<dimension<exp_multiply_t<Es, N, 1>...>>> {}; struct dimension_pow<dimension<Es...>, N> : std::type_identity<downcast_target<dimension<exp_multiply_t<Es, N, 1>...>>> {};
template<Dimension D, std::size_t N> template<Dimension D, std::size_t N>
using dimension_pow_t = dimension_pow<typename D::base_type, N>::type; using dimension_pow_t = dimension_pow<typename D::base_type, N>::type;

View File

@@ -26,14 +26,12 @@
namespace units { namespace units {
struct acceleration : make_dimension_t<exp<velocity, 1>, exp<base_dim_time, -1>> {}; struct acceleration : derived_dimension<acceleration, exp<velocity, 1>, exp<base_dim_time, -1>> {};
template<> struct downcast_traits<downcast_base_t<acceleration>> : std::type_identity<acceleration> {};
template<typename T> template<typename T>
concept bool Acceleration = QuantityOf<T, acceleration>; concept bool Acceleration = QuantityOf<T, acceleration>;
struct metre_per_second_sq : derived_unit<acceleration, metre, second> {}; struct metre_per_second_sq : derived_unit<metre_per_second_sq, acceleration, metre, second> {};
template<> struct downcast_traits<downcast_base_t<metre_per_second_sq>> : std::type_identity<metre_per_second_sq> {};
inline namespace literals { inline namespace literals {

View File

@@ -26,26 +26,16 @@
namespace units { namespace units {
struct area : make_dimension_t<exp<base_dim_length, 2>> {}; struct area : derived_dimension<area, exp<base_dim_length, 2>> {};
template<> struct downcast_traits<downcast_base_t<area>> : std::type_identity<area> {};
template<typename T> template<typename T>
concept bool Area = QuantityOf<T, area>; concept bool Area = QuantityOf<T, area>;
struct square_millimetre : derived_unit<area, millimetre> {}; struct square_millimetre : derived_unit<square_millimetre, area, millimetre> {};
template<> struct downcast_traits<downcast_base_t<square_millimetre>> : std::type_identity<square_millimetre> {}; struct square_centimetre : derived_unit<square_centimetre, area, centimetre> {};
struct square_metre : derived_unit<square_metre, area, metre> {};
struct square_centimetre : derived_unit<area, centimetre> {}; struct square_kilometre : derived_unit<square_kilometre, area, kilometre> {};
template<> struct downcast_traits<downcast_base_t<square_centimetre>> : std::type_identity<square_centimetre> {}; struct square_foot : derived_unit<square_foot, area, foot> {};
struct square_metre : derived_unit<area, metre> {};
template<> struct downcast_traits<downcast_base_t<square_metre>> : std::type_identity<square_metre> {};
struct square_kilometre : derived_unit<area, kilometre, metre> {};
template<> struct downcast_traits<downcast_base_t<square_kilometre>> : std::type_identity<square_kilometre> {};
struct square_foot : derived_unit<area, foot> {};
template<> struct downcast_traits<downcast_base_t<square_foot>> : std::type_identity<square_foot> {};
inline namespace literals { inline namespace literals {

View File

@@ -28,14 +28,12 @@
namespace units { namespace units {
struct capacitance : make_dimension_t<exp<electric_charge, 1>, exp<voltage, -1>> {}; struct capacitance : derived_dimension<capacitance, exp<electric_charge, 1>, exp<voltage, -1>> {};
template<> struct downcast_traits<downcast_base_t<capacitance>> : std::type_identity<capacitance> {};
template<typename T> template<typename T>
concept bool Capacitance = QuantityOf<T, capacitance>; concept bool Capacitance = QuantityOf<T, capacitance>;
struct farad : derived_unit<capacitance, kilogram, metre, second, ampere> {}; struct farad : derived_unit<farad, capacitance, kilogram, metre, second, ampere> {};
template<> struct downcast_traits<downcast_base_t<farad>> : std::type_identity<farad> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,14 +27,12 @@
namespace units { namespace units {
struct current : make_dimension_t<exp<base_dim_current, 1>> {}; struct current : derived_dimension<current, exp<base_dim_current, 1>> {};
template<> struct downcast_traits<downcast_base_t<current>> : std::type_identity<current> {};
template<typename T> template<typename T>
concept bool Current = QuantityOf<T, current>; concept bool Current = QuantityOf<T, current>;
struct ampere : unit<current> {}; struct ampere : derived_unit<ampere, current> {};
template<> struct downcast_traits<downcast_base_t<ampere>> : std::type_identity<ampere> {};
inline namespace literals { inline namespace literals {

View File

@@ -28,14 +28,12 @@
namespace units { namespace units {
struct electric_charge : make_dimension_t<exp<base_dim_time, 1>, exp<base_dim_current, 1>> {}; struct electric_charge : derived_dimension<electric_charge, exp<base_dim_time, 1>, exp<base_dim_current, 1>> {};
template<> struct downcast_traits<downcast_base_t<electric_charge>> : std::type_identity<electric_charge> {};
template<typename T> template<typename T>
concept bool ElectricCharge = QuantityOf<T, electric_charge>; concept bool ElectricCharge = QuantityOf<T, electric_charge>;
struct coulomb : derived_unit<electric_charge, second, ampere> {}; struct coulomb : derived_unit<coulomb, electric_charge, second, ampere> {};
template<> struct downcast_traits<downcast_base_t<coulomb>> : std::type_identity<coulomb> {};
inline namespace literals { inline namespace literals {

View File

@@ -28,14 +28,12 @@
namespace units { namespace units {
struct energy : make_dimension_t<exp<force, 1>, exp<length, 1>> {}; struct energy : derived_dimension<energy, exp<force, 1>, exp<length, 1>> {};
template<> struct downcast_traits<downcast_base_t<energy>> : std::type_identity<energy> {};
template<typename T> template<typename T>
concept bool Energy = QuantityOf<T, energy>; concept bool Energy = QuantityOf<T, energy>;
struct joule : derived_unit<energy, kilogram, metre, second> {}; struct joule : derived_unit<joule, energy, kilogram, metre, second> {};
template<> struct downcast_traits<downcast_base_t<joule>> : std::type_identity<joule> {};
inline namespace literals { inline namespace literals {

View File

@@ -28,14 +28,12 @@
namespace units { namespace units {
struct force : make_dimension_t<exp<base_dim_mass, 1>, exp<acceleration, 1>> {}; struct force : derived_dimension<force, exp<base_dim_mass, 1>, exp<acceleration, 1>> {};
template<> struct downcast_traits<downcast_base_t<force>> : std::type_identity<force> {};
template<typename T> template<typename T>
concept bool Force = QuantityOf<T, force>; concept bool Force = QuantityOf<T, force>;
struct newton : derived_unit<force, kilogram, metre, second> {}; struct newton : derived_unit<newton, force, kilogram, metre, second> {};
template<> struct downcast_traits<downcast_base_t<newton>> : std::type_identity<newton> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,29 +27,17 @@
namespace units { namespace units {
struct frequency : make_dimension_t<exp<base_dim_time, -1>> {}; struct frequency : derived_dimension<frequency, exp<base_dim_time, -1>> {};
template<> struct downcast_traits<downcast_base_t<frequency>> : std::type_identity<frequency> {};
template<typename T> template<typename T>
concept bool Frequency = QuantityOf<T, frequency>; concept bool Frequency = QuantityOf<T, frequency>;
struct hertz : derived_unit<frequency, second> {}; struct hertz : derived_unit<hertz, frequency, second> {};
template<> struct downcast_traits<downcast_base_t<hertz>> : std::type_identity<hertz> {}; struct millihertz : derived_unit<millihertz, milli<hertz>> {};
struct kilohertz : derived_unit<kilohertz, kilo<hertz>> {};
struct millihertz : milli<hertz> {}; struct megahertz : derived_unit<megahertz, mega<hertz>> {};
template<> struct downcast_traits<downcast_base_t<millihertz>> : std::type_identity<millihertz> {}; struct gigahertz : derived_unit<gigahertz, giga<hertz>> {};
struct terahertz : derived_unit<terahertz, tera<hertz>> {};
struct kilohertz : kilo<hertz> {};
template<> struct downcast_traits<downcast_base_t<kilohertz>> : std::type_identity<kilohertz> {};
struct megahertz : mega<hertz> {};
template<> struct downcast_traits<downcast_base_t<megahertz>> : std::type_identity<megahertz> {};
struct gigahertz : giga<hertz> {};
template<> struct downcast_traits<downcast_base_t<gigahertz>> : std::type_identity<gigahertz> {};
struct terahertz : tera<hertz> {};
template<> struct downcast_traits<downcast_base_t<terahertz>> : std::type_identity<terahertz> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,24 +27,16 @@
namespace units { namespace units {
struct length : make_dimension_t<exp<base_dim_length, 1>> {}; struct length : derived_dimension<length, exp<base_dim_length, 1>> {};
template<> struct downcast_traits<downcast_base_t<length>> : std::type_identity<length> {};
template<typename T> template<typename T>
concept bool Length = QuantityOf<T, length>; concept bool Length = QuantityOf<T, length>;
// SI units // SI units
struct metre : unit<length> {}; struct metre : derived_unit<metre, length> {};
template<> struct downcast_traits<downcast_base_t<metre>> : std::type_identity<metre> {}; struct millimetre : derived_unit<millimetre, milli<metre>> {};
struct centimetre : derived_unit<centimetre, centi<metre>> {};
struct millimetre : milli<metre> {}; struct kilometre : derived_unit<kilometre, kilo<metre>> {};
template<> struct downcast_traits<downcast_base_t<millimetre>> : std::type_identity<millimetre> {};
struct centimetre : centi<metre> {};
template<> struct downcast_traits<downcast_base_t<centimetre>> : std::type_identity<centimetre> {};
struct kilometre : kilo<metre> {};
template<> struct downcast_traits<downcast_base_t<kilometre>> : std::type_identity<kilometre> {};
inline namespace literals { inline namespace literals {
@@ -67,17 +59,10 @@ namespace units {
} // namespace literals } // namespace literals
// US customary units // US customary units
struct yard : unit<length, ratio<9'144, 10'000>> {}; struct yard : derived_unit<yard, length, ratio<9'144, 10'000>> {};
template<> struct downcast_traits<downcast_base_t<yard>> : std::type_identity<yard> {}; struct foot : derived_unit<foot, length, ratio_multiply<ratio<1, 3>, yard::ratio>> {};
struct inch : derived_unit<inch, length, ratio_multiply<ratio<1, 12>, foot::ratio>> {};
struct foot : unit<length, ratio_multiply<ratio<1, 3>, yard::ratio>> {}; struct mile : derived_unit<mile, length, ratio_multiply<ratio<1'760>, yard::ratio>> {};
template<> struct downcast_traits<downcast_base_t<foot>> : std::type_identity<foot> {};
struct inch : unit<length, ratio_multiply<ratio<1, 12>, foot::ratio>> {};
template<> struct downcast_traits<downcast_base_t<inch>> : std::type_identity<inch> {};
struct mile : unit<length, ratio_multiply<ratio<1'760>, yard::ratio>> {};
template<> struct downcast_traits<downcast_base_t<mile>> : std::type_identity<mile> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,14 +27,12 @@
namespace units { namespace units {
struct luminous_intensity : make_dimension_t<exp<base_dim_luminous_intensity, 1>> {}; struct luminous_intensity : derived_dimension<luminous_intensity, exp<base_dim_luminous_intensity, 1>> {};
template<> struct downcast_traits<downcast_base_t<luminous_intensity>> : std::type_identity<luminous_intensity> {};
template<typename T> template<typename T>
concept bool LuminousIntensity = QuantityOf<T, luminous_intensity>; concept bool LuminousIntensity = QuantityOf<T, luminous_intensity>;
struct candela : unit<luminous_intensity> {}; struct candela : derived_unit<candela, luminous_intensity> {};
template<> struct downcast_traits<downcast_base_t<candela>> : std::type_identity<candela> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,17 +27,13 @@
namespace units { namespace units {
struct mass : make_dimension_t<exp<base_dim_mass, 1>> {}; struct mass : derived_dimension<mass, exp<base_dim_mass, 1>> {};
template<> struct downcast_traits<downcast_base_t<mass>> : std::type_identity<mass> {};
template<typename T> template<typename T>
concept bool Mass = QuantityOf<T, mass>; concept bool Mass = QuantityOf<T, mass>;
struct gram : unit<mass, ratio<1, 1000>> {}; struct gram : derived_unit<gram, mass, ratio<1, 1000>> {};
template<> struct downcast_traits<downcast_base_t<gram>> : std::type_identity<gram> {}; struct kilogram : derived_unit<kilogram, kilo<gram>> {};
struct kilogram : kilo<gram> {};
template<> struct downcast_traits<downcast_base_t<kilogram>> : std::type_identity<kilogram> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,14 +27,12 @@
namespace units { namespace units {
struct power : make_dimension_t<exp<energy, 1>, exp<base_dim_time, -1>> {}; struct power : derived_dimension<power, exp<energy, 1>, exp<base_dim_time, -1>> {};
template<> struct downcast_traits<downcast_base_t<power>> : std::type_identity<power> {};
template<typename T> template<typename T>
concept bool Power = QuantityOf<T, power>; concept bool Power = QuantityOf<T, power>;
struct watt : derived_unit<power, kilogram, metre, second> {}; struct watt : derived_unit<watt, power, kilogram, metre, second> {};
template<> struct downcast_traits<downcast_base_t<watt>> : std::type_identity<watt> {};
inline namespace literals { inline namespace literals {

View File

@@ -28,14 +28,12 @@
namespace units { namespace units {
struct pressure : make_dimension_t<exp<force, 1>, exp<area, -1>> {}; struct pressure : derived_dimension<pressure, exp<force, 1>, exp<area, -1>> {};
template<> struct downcast_traits<downcast_base_t<pressure>> : std::type_identity<pressure> {};
template<typename T> template<typename T>
concept bool Pressure = QuantityOf<T, pressure>; concept bool Pressure = QuantityOf<T, pressure>;
struct pascal : derived_unit<pressure, kilogram, metre, second> {}; struct pascal : derived_unit<pascal, pressure, kilogram, metre, second> {};
template<> struct downcast_traits<downcast_base_t<pascal>> : std::type_identity<pascal> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,14 +27,12 @@
namespace units { namespace units {
struct substance : make_dimension_t<exp<base_dim_substance, 1>> {}; struct substance : derived_dimension<substance, exp<base_dim_substance, 1>> {};
template<> struct downcast_traits<downcast_base_t<substance>> : std::type_identity<substance> {};
template<typename T> template<typename T>
concept bool Substance = QuantityOf<T, substance>; concept bool Substance = QuantityOf<T, substance>;
struct mole : unit<substance> {}; struct mole : derived_unit<mole, substance> {};
template<> struct downcast_traits<downcast_base_t<mole>> : std::type_identity<mole> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,14 +27,12 @@
namespace units { namespace units {
struct temperature : make_dimension_t<exp<base_dim_temperature, 1>> {}; struct temperature : derived_dimension<temperature, exp<base_dim_temperature, 1>> {};
template<> struct downcast_traits<downcast_base_t<temperature>> : std::type_identity<temperature> {};
template<typename T> template<typename T>
concept bool ThermodynamicTemperature = QuantityOf<T, temperature>; concept bool ThermodynamicTemperature = QuantityOf<T, temperature>;
struct kelvin : unit<temperature> {}; struct kelvin : derived_unit<kelvin, temperature> {};
template<> struct downcast_traits<downcast_base_t<kelvin>> : std::type_identity<kelvin> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,29 +27,17 @@
namespace units { namespace units {
struct time : make_dimension_t<exp<base_dim_time, 1>> {}; struct time : derived_dimension<time, exp<base_dim_time, 1>> {};
template<> struct downcast_traits<downcast_base_t<time>> : std::type_identity<time> {};
template<typename T> template<typename T>
concept bool Time = QuantityOf<T, time>; concept bool Time = QuantityOf<T, time>;
struct second : unit<time> {}; struct second : derived_unit<second, time> {};
template<> struct downcast_traits<downcast_base_t<second>> : std::type_identity<second> {}; struct nanosecond : derived_unit<nanosecond, nano<second>> {};
struct microsecond : derived_unit<microsecond, micro<second>> {};
struct nanosecond : nano<second> {}; struct millisecond : derived_unit<millisecond, milli<second>> {};
template<> struct downcast_traits<downcast_base_t<nanosecond>> : std::type_identity<nanosecond> {}; struct minute : derived_unit<minute, time, ratio<60>> {};
struct hour : derived_unit<hour, time, ratio<3600>> {};
struct microsecond : micro<second> {};
template<> struct downcast_traits<downcast_base_t<microsecond>> : std::type_identity<microsecond> {};
struct millisecond : milli<second> {};
template<> struct downcast_traits<downcast_base_t<millisecond>> : std::type_identity<millisecond> {};
struct minute : unit<time, ratio<60>> {};
template<> struct downcast_traits<downcast_base_t<minute>> : std::type_identity<minute> {};
struct hour : unit<time, ratio<3600>> {};
template<> struct downcast_traits<downcast_base_t<hour>> : std::type_identity<hour> {};
inline namespace literals { inline namespace literals {

View File

@@ -27,20 +27,14 @@
namespace units { namespace units {
struct velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; struct velocity : derived_dimension<velocity, exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
template<> struct downcast_traits<downcast_base_t<velocity>> : std::type_identity<velocity> {};
template<typename T> template<typename T>
concept bool Velocity = QuantityOf<T, velocity>; concept bool Velocity = QuantityOf<T, velocity>;
struct metre_per_second : derived_unit<velocity, metre, second> {}; struct metre_per_second : derived_unit<metre_per_second, velocity, metre, second> {};
template<> struct downcast_traits<downcast_base_t<metre_per_second>> : std::type_identity<metre_per_second> {}; struct kilometre_per_hour : derived_unit<kilometre_per_hour, velocity, kilometre, hour> {};
struct mile_per_hour : derived_unit<mile_per_hour, velocity, mile, hour> {};
struct kilometre_per_hour : derived_unit<velocity, kilometre, hour> {};
template<> struct downcast_traits<downcast_base_t<kilometre_per_hour>> : std::type_identity<kilometre_per_hour> {};
struct mile_per_hour : derived_unit<velocity, mile, hour> {};
template<> struct downcast_traits<downcast_base_t<mile_per_hour>> : std::type_identity<mile_per_hour> {};
inline namespace literals { inline namespace literals {

View File

@@ -30,14 +30,12 @@
namespace units { namespace units {
struct voltage : make_dimension_t<exp<power, 1>, exp<base_dim_current, -1>> {}; struct voltage : derived_dimension<voltage, exp<power, 1>, exp<base_dim_current, -1>> {};
template<> struct downcast_traits<downcast_base_t<voltage>> : std::type_identity<voltage> {};
template<typename T> template<typename T>
concept bool Voltage = QuantityOf<T, voltage>; concept bool Voltage = QuantityOf<T, voltage>;
struct volt : derived_unit<voltage, kilogram, metre, second, ampere> {}; struct volt : derived_unit<volt, voltage, kilogram, metre, second, ampere> {};
template<> struct downcast_traits<downcast_base_t<volt>> : std::type_identity<volt> {};
inline namespace literals { inline namespace literals {

View File

@@ -26,26 +26,16 @@
namespace units { namespace units {
struct volume : make_dimension_t<exp<base_dim_length, 3>> {}; struct volume : derived_dimension<volume, exp<base_dim_length, 3>> {};
template<> struct downcast_traits<downcast_base_t<volume>> : std::type_identity<volume> {};
template<typename T> template<typename T>
concept bool Volume = QuantityOf<T, volume>; concept bool Volume = QuantityOf<T, volume>;
struct cubic_millimetre : derived_unit<volume, millimetre> {}; struct cubic_millimetre : derived_unit<cubic_millimetre, volume, millimetre> {};
template<> struct downcast_traits<downcast_base_t<cubic_millimetre>> : std::type_identity<cubic_millimetre> {}; struct cubic_centimetre : derived_unit<cubic_centimetre, volume, centimetre> {};
struct cubic_metre : derived_unit<cubic_metre, volume, metre> {};
struct cubic_centimetre : derived_unit<volume, centimetre> {}; struct cubic_kilometre : derived_unit<cubic_kilometre, volume, kilometre, metre> {};
template<> struct downcast_traits<downcast_base_t<cubic_centimetre>> : std::type_identity<cubic_centimetre> {}; struct cubic_foot : derived_unit<cubic_foot, volume, foot> {};
struct cubic_metre : derived_unit<volume, metre> {};
template<> struct downcast_traits<downcast_base_t<cubic_metre>> : std::type_identity<cubic_metre> {};
struct cubic_kilometre : derived_unit<volume, kilometre, metre> {};
template<> struct downcast_traits<downcast_base_t<cubic_kilometre>> : std::type_identity<cubic_kilometre> {};
struct cubic_foot : derived_unit<volume, foot> {};
template<> struct downcast_traits<downcast_base_t<cubic_foot>> : std::type_identity<cubic_foot> {};
inline namespace literals { inline namespace literals {

View File

@@ -32,7 +32,7 @@ namespace units {
{ {
using dim = dimension_pow_t<typename U::dimension, N>; using dim = dimension_pow_t<typename U::dimension, N>;
using r = ratio_pow<typename U::ratio, N>; using r = ratio_pow<typename U::ratio, N>;
return quantity<downcast_traits_t<unit<dim, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N))); return quantity<downcast_target<unit<dim, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
} }
template<typename U, typename Rep> template<typename U, typename Rep>
@@ -40,7 +40,7 @@ namespace units {
{ {
using dim = dimension_sqrt_t<typename U::dimension>; using dim = dimension_sqrt_t<typename U::dimension>;
using r = ratio_sqrt<typename U::ratio>; using r = ratio_sqrt<typename U::ratio>;
return quantity<downcast_traits_t<unit<dim, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count()))); return quantity<downcast_target<unit<dim, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
} }
} // namespace units } // namespace units

View File

@@ -71,7 +71,7 @@ namespace units {
template<typename U1, typename Rep1, typename U2, typename Rep2, typename Rep> template<typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
requires same_dim<typename U1::dimension, typename U2::dimension> requires same_dim<typename U1::dimension, typename U2::dimension>
struct common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> { struct common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> {
using type = quantity<downcast_traits_t<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>, Rep>; using type = quantity<downcast_target<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>, Rep>;
}; };
template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>> template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
@@ -307,7 +307,7 @@ namespace units {
{ {
using dim = dimension_multiply_t<typename U1::dimension, typename U2::dimension>; using dim = dimension_multiply_t<typename U1::dimension, typename U2::dimension>;
using common_rep = decltype(lhs.count() * rhs.count()); using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<downcast_traits_t<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>; using ret = quantity<downcast_target<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
return ret(lhs.count() * rhs.count()); return ret(lhs.count() * rhs.count());
} }
@@ -321,7 +321,7 @@ namespace units {
using dim = dim_invert_t<typename U::dimension>; using dim = dim_invert_t<typename U::dimension>;
using common_rep = decltype(v / q.count()); using common_rep = decltype(v / q.count());
using ret = quantity<downcast_traits_t<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>; using ret = quantity<downcast_target<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
using den = quantity<U, common_rep>; using den = quantity<U, common_rep>;
return ret(v / den(q).count()); return ret(v / den(q).count());
} }
@@ -362,7 +362,7 @@ namespace units {
using common_rep = decltype(lhs.count() / rhs.count()); using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide_t<typename U1::dimension, typename U2::dimension>; using dim = dimension_divide_t<typename U1::dimension, typename U2::dimension>;
using ret = quantity<downcast_traits_t<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>; using ret = quantity<downcast_target<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
return ret(lhs.count() / rhs.count()); return ret(lhs.count() / rhs.count());
} }

View File

@@ -52,8 +52,7 @@ namespace units {
std::is_empty_v<T> && std::is_empty_v<T> &&
detail::is_unit<downcast_base_t<T>>; detail::is_unit<downcast_base_t<T>>;
// make_derived_unit
// derived_unit
namespace detail { namespace detail {
@@ -109,12 +108,30 @@ namespace units {
using ratio = ratio_op<rest_ratio, E::num, E::den, e_ratio>::ratio; using ratio = ratio_op<rest_ratio, E::num, E::den, e_ratio>::ratio;
}; };
template<Dimension D, Unit... Us>
using make_derived_unit = unit<D, typename detail::derived_ratio<typename D::base_type, Us...>::ratio>;
} }
template<Dimension D, Unit... Us> // derived_unit
using derived_unit = unit<D, typename detail::derived_ratio<typename D::base_type, Us...>::ratio>;
template<typename Child, typename...>
struct derived_unit;
template<typename Child, Dimension D>
struct derived_unit<Child, D> : downcast_helper<Child, unit<D, ratio<1>>> {};
template<typename Child, Dimension D, Ratio R>
struct derived_unit<Child, D, R> : downcast_helper<Child, unit<D, R>> {};
template<typename Child, Unit U>
struct derived_unit<Child, U> : downcast_helper<Child, U> {};
template<typename Child, Dimension D, Unit U, Unit... Us>
struct derived_unit<Child, D, U, Us...> : downcast_helper<Child, detail::make_derived_unit<D, U, Us...>> {};
// SI prefixes
// prefixes
template<Unit U> using atto = unit<typename U::dimension, ratio_multiply<typename U::ratio, ratio<1, std::atto::den>>>; template<Unit U> using atto = unit<typename U::dimension, ratio_multiply<typename U::ratio, ratio<1, std::atto::den>>>;
template<Unit U> using femto = unit<typename U::dimension, ratio_multiply<typename U::ratio, ratio<1, std::femto::den>>>; template<Unit U> using femto = unit<typename U::dimension, ratio_multiply<typename U::ratio, ratio<1, std::femto::den>>>;
template<Unit U> using pico = unit<typename U::dimension, ratio_multiply<typename U::ratio, ratio<1, std::pico::den>>>; template<Unit U> using pico = unit<typename U::dimension, ratio_multiply<typename U::ratio, ratio<1, std::pico::den>>>;

View File

@@ -30,13 +30,13 @@ namespace {
struct base_dim_digital_information { static constexpr const char* value = "digital information"; }; struct base_dim_digital_information { static constexpr const char* value = "digital information"; };
struct digital_information : units::make_dimension_t<units::exp<base_dim_digital_information, 1>> {}; struct digital_information : units::derived_dimension<digital_information, units::exp<base_dim_digital_information, 1>> {};
template<typename T> template<typename T>
concept bool DigitalInformation = units::QuantityOf<T, digital_information>; concept bool DigitalInformation = units::QuantityOf<T, digital_information>;
struct bit : units::unit<digital_information> {}; struct bit : units::derived_unit<bit, digital_information> {};
struct byte : units::unit<digital_information, units::ratio<8>> {}; struct byte : units::derived_unit<byte, digital_information, units::ratio<8>> {};
inline namespace literals { inline namespace literals {
@@ -49,10 +49,6 @@ namespace {
} }
} }
template<> struct units::downcast_traits<units::downcast_base_t<digital_information>> : std::type_identity<digital_information> {};
template<> struct units::downcast_traits<units::downcast_base_t<bit>> : std::type_identity<bit> {};
template<> struct units::downcast_traits<units::downcast_base_t<::byte>> : std::type_identity<::byte> {};
namespace { namespace {
static_assert(1_B == 8_b); static_assert(1_B == 8_b);
@@ -64,24 +60,14 @@ namespace {
using namespace units; using namespace units;
// power spectral density // power spectral density
struct power_spectral_density : make_dimension_t<units::exp<voltage, 2>, units::exp<frequency, -1>> {}; struct power_spectral_density : derived_dimension<power_spectral_density, units::exp<voltage, 2>, units::exp<frequency, -1>> {};
struct sq_volt_per_hertz : unit<power_spectral_density> {}; struct sq_volt_per_hertz : derived_unit<sq_volt_per_hertz, power_spectral_density> {};
// amplitude spectral density // amplitude spectral density
struct amplitude_spectral_density : make_dimension_t<units::exp<voltage, 1>, units::exp<frequency, -1, 2>> {}; struct amplitude_spectral_density : derived_dimension<amplitude_spectral_density, units::exp<voltage, 1>, units::exp<frequency, -1, 2>> {};
// todo: add support for derived_unit // todo: add support for derived_unit
//struct volt_per_sq_hertz : derived_unit<amplitude_spectral_density, kilogram, metre, second, ampere> {}; //struct volt_per_sq_hertz : derived_unit<amplitude_spectral_density, kilogram, metre, second, ampere> {};
struct volt_per_sqrt_hertz : unit<amplitude_spectral_density> {}; struct volt_per_sqrt_hertz : derived_unit<volt_per_sqrt_hertz, amplitude_spectral_density> {};
}
namespace units {
template<> struct downcast_traits<downcast_base_t<power_spectral_density>> : std::type_identity<power_spectral_density> {};
template<> struct downcast_traits<downcast_base_t<sq_volt_per_hertz>> : std::type_identity<sq_volt_per_hertz> {};
template<> struct downcast_traits<downcast_base_t<amplitude_spectral_density>> : std::type_identity<amplitude_spectral_density> {};
template<> struct downcast_traits<downcast_base_t<volt_per_sqrt_hertz>> : std::type_identity<volt_per_sqrt_hertz> {};
} }
namespace { namespace {

View File

@@ -54,23 +54,23 @@ namespace {
// make_dimension // make_dimension
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>>, dimension<exp<d0, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>>, dimension<exp<d0, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>, exp<d1, 1>>, dimension<exp<d0, 1>, exp<d1, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>, exp<d1, 1>>, dimension<exp<d0, 1>, exp<d1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d1, 1>, exp<d0, 1>>, dimension<exp<d0, 1>, exp<d1, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d1, 1>, exp<d0, 1>>, dimension<exp<d0, 1>, exp<d1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d1, 1>, exp<d1, 1>>, dimension<exp<d1, 2>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d1, 1>, exp<d1, 1>>, dimension<exp<d1, 2>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d1, 1>, exp<d1, -1>>, dimension<>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d1, 1>, exp<d1, -1>>, dimension<>>);
static_assert(std::is_same_v<make_dimension_t<exp<d1, 1>, exp<d1, 1, 2>>, dimension<exp<d1, 3, 2>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d1, 1>, exp<d1, 1, 2>>, dimension<exp<d1, 3, 2>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d1, 1, 2>, exp<d1, 1, 2>>, dimension<exp<d1, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d1, 1, 2>, exp<d1, 1, 2>>, dimension<exp<d1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d1, 2>, exp<d1, 1, 2>>, dimension<exp<d1, 5, 2>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d1, 2>, exp<d1, 1, 2>>, dimension<exp<d1, 5, 2>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d0, 1>, exp<d1, 1>>, dimension<exp<d0, 2>, exp<d1, 2>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d0, 1>, exp<d1, 1>>, dimension<exp<d0, 2>, exp<d1, 2>>>);
static_assert( static_assert(
std::is_same_v<make_dimension_t<exp<d0, -1>, exp<d1, -1>, exp<d0, -1>, exp<d1, -1>>, dimension<exp<d0, -2>, exp<d1, -2>>>); std::is_same_v<detail::make_dimension_t<exp<d0, -1>, exp<d1, -1>, exp<d0, -1>, exp<d1, -1>>, dimension<exp<d0, -2>, exp<d1, -2>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d1, -1>>, dimension<exp<d0, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d1, -1>>, dimension<exp<d0, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>, exp<d0, -1>, exp<d1, 1>>, dimension<exp<d1, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>, exp<d0, -1>, exp<d1, 1>>, dimension<exp<d1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d0, -1>>, dimension<exp<d1, 1>>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d0, -1>>, dimension<exp<d1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d0, -1>, exp<d1, -1>>, dimension<>>); static_assert(std::is_same_v<detail::make_dimension_t<exp<d0, 1>, exp<d1, 1>, exp<d0, -1>, exp<d1, -1>>, dimension<>>);
// dimension_multiply // dimension_multiply