mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-04 04:44:27 +02:00
Downcasting facility refactored so the user does not have to write the boilerplate code anymore
This commit is contained in:
@@ -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
|
||||
|
261
doc/DESIGN.md
261
doc/DESIGN.md
@@ -82,7 +82,7 @@ template<Exponent... 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:
|
||||
|
||||
```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<Exponent... Es>
|
||||
struct make_dimension {
|
||||
using type = /* unspecified */;
|
||||
};
|
||||
|
||||
template<Exponent... Es>
|
||||
using make_dimension_t = make_dimension<Es...>::type;
|
||||
template<typename Child, Exponent... Es>
|
||||
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<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:
|
||||
- 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<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
|
||||
|
||||
```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
|
||||
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<Dimension D1, Dimension D2>
|
||||
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`
|
||||
|
||||
@@ -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`:
|
||||
|
||||
```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:
|
||||
- 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<metre> {};
|
||||
template<typename Child, Dimension D>
|
||||
struct derived_unit<Child, D>;
|
||||
```
|
||||
|
||||
- derived units
|
||||
```cpp
|
||||
struct metre : derived_unit<metre, length> {};
|
||||
```
|
||||
|
||||
- helper to create other units for a specified dimension
|
||||
|
||||
```cpp
|
||||
struct kilometre_per_hour : derived_unit<velocity, kilometre, hour> {};
|
||||
```
|
||||
template<typename Child, Dimension D, Ratio R>
|
||||
struct derived_unit<Child, D, R>;
|
||||
```
|
||||
|
||||
`units::Unit` is a Concept that is satisfied by a type that is empty and publicly
|
||||
```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:
|
||||
|
||||
```cpp
|
||||
@@ -284,11 +316,11 @@ concept Unit =
|
||||
expressed in a specific unit of that dimension:
|
||||
|
||||
```cpp
|
||||
template<Unit U, Scalar Rep>
|
||||
template<Unit U, Scalar Rep = double>
|
||||
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<Unit ToU, Scalar ToRep = double, typename U, typename Rep>
|
||||
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
|
||||
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<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
|
||||
template<typename BaseType>
|
||||
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<typename T>
|
||||
concept Downcastable =
|
||||
requires {
|
||||
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>
|
||||
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"};
|
||||
```
|
||||
|
||||
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<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> {};
|
||||
struct digital_information : units::derived_dimension<digital_information, units::exp<base_dim_digital_information, 1>> {};
|
||||
```
|
||||
|
||||
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>;
|
||||
```
|
||||
|
||||
3. Define units and provide downcasting traits for them:
|
||||
3. Define units and register them to a downcasting facility:
|
||||
|
||||
```cpp
|
||||
struct bit : units::unit<digital_information> {};
|
||||
template<> struct units::downcast_traits<units::downcast_base_t<bit>> : units::std::type_identity_t<bit> {};
|
||||
|
||||
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> {};
|
||||
struct bit : units::derived_unit<bit, digital_information> {};
|
||||
struct byte : units::derived_unit<byte, digital_information, units::ratio<8>> {};
|
||||
```
|
||||
|
||||
4. Provide user-defined literals for the most important units:
|
||||
|
@@ -30,6 +30,7 @@ namespace units {
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using base_type = BaseType;
|
||||
friend auto downcast_guide(downcast_base);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -39,13 +40,33 @@ namespace units {
|
||||
} &&
|
||||
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>
|
||||
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
|
||||
|
@@ -156,13 +156,11 @@ namespace units {
|
||||
struct dim_invert;
|
||||
|
||||
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>
|
||||
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
|
||||
|
||||
namespace detail {
|
||||
@@ -224,15 +222,22 @@ namespace units {
|
||||
using type = extract_t<exp<downcast_base_t<Dim>, Num, Den>, ERest...>;
|
||||
};
|
||||
|
||||
template<Exponent... Es>
|
||||
struct make_dimension {
|
||||
using type = detail::dim_consolidate_t<type_list_sort<detail::extract_t<Es...>, exp_less>>;
|
||||
};
|
||||
|
||||
template<Exponent... Es>
|
||||
using make_dimension_t = make_dimension<Es...>::type;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Exponent... Es>
|
||||
struct make_dimension {
|
||||
using type = detail::dim_consolidate_t<type_list_sort<detail::extract_t<Es...>, exp_less>>;
|
||||
};
|
||||
// derived_dimension
|
||||
|
||||
template<Exponent... Es>
|
||||
using make_dimension_t = make_dimension<Es...>::type;
|
||||
template<typename Child, Exponent... Es>
|
||||
struct derived_dimension : downcast_helper<Child, detail::make_dimension_t<Es...>> {};
|
||||
|
||||
// merge_dimension
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
struct merge_dimension {
|
||||
@@ -248,7 +253,7 @@ namespace units {
|
||||
struct dimension_multiply;
|
||||
|
||||
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>
|
||||
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;
|
||||
|
||||
// dimension_sqrt
|
||||
|
||||
template<Dimension D>
|
||||
struct dimension_sqrt;
|
||||
|
||||
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>
|
||||
using dimension_sqrt_t = dimension_sqrt<typename D::base_type>::type;
|
||||
|
||||
// dimension_pow
|
||||
|
||||
template<Dimension D, std::size_t N>
|
||||
struct dimension_pow;
|
||||
|
||||
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>
|
||||
using dimension_pow_t = dimension_pow<typename D::base_type, N>::type;
|
||||
|
@@ -26,14 +26,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct acceleration : make_dimension_t<exp<velocity, 1>, exp<base_dim_time, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<acceleration>> : std::type_identity<acceleration> {};
|
||||
struct acceleration : derived_dimension<acceleration, exp<velocity, 1>, exp<base_dim_time, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Acceleration = QuantityOf<T, acceleration>;
|
||||
|
||||
struct metre_per_second_sq : derived_unit<acceleration, metre, second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<metre_per_second_sq>> : std::type_identity<metre_per_second_sq> {};
|
||||
struct metre_per_second_sq : derived_unit<metre_per_second_sq, acceleration, metre, second> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -26,26 +26,16 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct area : make_dimension_t<exp<base_dim_length, 2>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<area>> : std::type_identity<area> {};
|
||||
struct area : derived_dimension<area, exp<base_dim_length, 2>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Area = QuantityOf<T, area>;
|
||||
|
||||
struct square_millimetre : derived_unit<area, millimetre> {};
|
||||
template<> struct downcast_traits<downcast_base_t<square_millimetre>> : std::type_identity<square_millimetre> {};
|
||||
|
||||
struct square_centimetre : derived_unit<area, centimetre> {};
|
||||
template<> struct downcast_traits<downcast_base_t<square_centimetre>> : std::type_identity<square_centimetre> {};
|
||||
|
||||
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> {};
|
||||
struct square_millimetre : derived_unit<square_millimetre, area, millimetre> {};
|
||||
struct square_centimetre : derived_unit<square_centimetre, area, centimetre> {};
|
||||
struct square_metre : derived_unit<square_metre, area, metre> {};
|
||||
struct square_kilometre : derived_unit<square_kilometre, area, kilometre> {};
|
||||
struct square_foot : derived_unit<square_foot, area, foot> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -28,14 +28,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct capacitance : make_dimension_t<exp<electric_charge, 1>, exp<voltage, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<capacitance>> : std::type_identity<capacitance> {};
|
||||
struct capacitance : derived_dimension<capacitance, exp<electric_charge, 1>, exp<voltage, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Capacitance = QuantityOf<T, capacitance>;
|
||||
|
||||
struct farad : derived_unit<capacitance, kilogram, metre, second, ampere> {};
|
||||
template<> struct downcast_traits<downcast_base_t<farad>> : std::type_identity<farad> {};
|
||||
struct farad : derived_unit<farad, capacitance, kilogram, metre, second, ampere> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,14 +27,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct current : make_dimension_t<exp<base_dim_current, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<current>> : std::type_identity<current> {};
|
||||
struct current : derived_dimension<current, exp<base_dim_current, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Current = QuantityOf<T, current>;
|
||||
|
||||
struct ampere : unit<current> {};
|
||||
template<> struct downcast_traits<downcast_base_t<ampere>> : std::type_identity<ampere> {};
|
||||
struct ampere : derived_unit<ampere, current> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -28,14 +28,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct electric_charge : make_dimension_t<exp<base_dim_time, 1>, exp<base_dim_current, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<electric_charge>> : std::type_identity<electric_charge> {};
|
||||
struct electric_charge : derived_dimension<electric_charge, exp<base_dim_time, 1>, exp<base_dim_current, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool ElectricCharge = QuantityOf<T, electric_charge>;
|
||||
|
||||
struct coulomb : derived_unit<electric_charge, second, ampere> {};
|
||||
template<> struct downcast_traits<downcast_base_t<coulomb>> : std::type_identity<coulomb> {};
|
||||
struct coulomb : derived_unit<coulomb, electric_charge, second, ampere> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -28,14 +28,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct energy : make_dimension_t<exp<force, 1>, exp<length, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<energy>> : std::type_identity<energy> {};
|
||||
struct energy : derived_dimension<energy, exp<force, 1>, exp<length, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Energy = QuantityOf<T, energy>;
|
||||
|
||||
struct joule : derived_unit<energy, kilogram, metre, second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<joule>> : std::type_identity<joule> {};
|
||||
struct joule : derived_unit<joule, energy, kilogram, metre, second> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -28,14 +28,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct force : make_dimension_t<exp<base_dim_mass, 1>, exp<acceleration, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<force>> : std::type_identity<force> {};
|
||||
struct force : derived_dimension<force, exp<base_dim_mass, 1>, exp<acceleration, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Force = QuantityOf<T, force>;
|
||||
|
||||
struct newton : derived_unit<force, kilogram, metre, second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<newton>> : std::type_identity<newton> {};
|
||||
struct newton : derived_unit<newton, force, kilogram, metre, second> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,29 +27,17 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct frequency : make_dimension_t<exp<base_dim_time, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<frequency>> : std::type_identity<frequency> {};
|
||||
struct frequency : derived_dimension<frequency, exp<base_dim_time, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Frequency = QuantityOf<T, frequency>;
|
||||
|
||||
struct hertz : derived_unit<frequency, second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<hertz>> : std::type_identity<hertz> {};
|
||||
|
||||
struct millihertz : milli<hertz> {};
|
||||
template<> struct downcast_traits<downcast_base_t<millihertz>> : std::type_identity<millihertz> {};
|
||||
|
||||
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> {};
|
||||
struct hertz : derived_unit<hertz, frequency, second> {};
|
||||
struct millihertz : derived_unit<millihertz, milli<hertz>> {};
|
||||
struct kilohertz : derived_unit<kilohertz, kilo<hertz>> {};
|
||||
struct megahertz : derived_unit<megahertz, mega<hertz>> {};
|
||||
struct gigahertz : derived_unit<gigahertz, giga<hertz>> {};
|
||||
struct terahertz : derived_unit<terahertz, tera<hertz>> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,24 +27,16 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct length : make_dimension_t<exp<base_dim_length, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<length>> : std::type_identity<length> {};
|
||||
struct length : derived_dimension<length, exp<base_dim_length, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Length = QuantityOf<T, length>;
|
||||
|
||||
// SI units
|
||||
struct metre : unit<length> {};
|
||||
template<> struct downcast_traits<downcast_base_t<metre>> : std::type_identity<metre> {};
|
||||
|
||||
struct millimetre : milli<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> {};
|
||||
struct metre : derived_unit<metre, length> {};
|
||||
struct millimetre : derived_unit<millimetre, milli<metre>> {};
|
||||
struct centimetre : derived_unit<centimetre, centi<metre>> {};
|
||||
struct kilometre : derived_unit<kilometre, kilo<metre>> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
@@ -67,17 +59,10 @@ namespace units {
|
||||
} // namespace literals
|
||||
|
||||
// US customary units
|
||||
struct yard : unit<length, ratio<9'144, 10'000>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<yard>> : std::type_identity<yard> {};
|
||||
|
||||
struct foot : unit<length, ratio_multiply<ratio<1, 3>, 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> {};
|
||||
struct yard : derived_unit<yard, length, ratio<9'144, 10'000>> {};
|
||||
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 mile : derived_unit<mile, length, ratio_multiply<ratio<1'760>, yard::ratio>> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,14 +27,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct luminous_intensity : make_dimension_t<exp<base_dim_luminous_intensity, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<luminous_intensity>> : std::type_identity<luminous_intensity> {};
|
||||
struct luminous_intensity : derived_dimension<luminous_intensity, exp<base_dim_luminous_intensity, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool LuminousIntensity = QuantityOf<T, luminous_intensity>;
|
||||
|
||||
struct candela : unit<luminous_intensity> {};
|
||||
template<> struct downcast_traits<downcast_base_t<candela>> : std::type_identity<candela> {};
|
||||
struct candela : derived_unit<candela, luminous_intensity> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,17 +27,13 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct mass : make_dimension_t<exp<base_dim_mass, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<mass>> : std::type_identity<mass> {};
|
||||
struct mass : derived_dimension<mass, exp<base_dim_mass, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Mass = QuantityOf<T, mass>;
|
||||
|
||||
struct gram : unit<mass, ratio<1, 1000>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<gram>> : std::type_identity<gram> {};
|
||||
|
||||
struct kilogram : kilo<gram> {};
|
||||
template<> struct downcast_traits<downcast_base_t<kilogram>> : std::type_identity<kilogram> {};
|
||||
struct gram : derived_unit<gram, mass, ratio<1, 1000>> {};
|
||||
struct kilogram : derived_unit<kilogram, kilo<gram>> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,14 +27,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct power : make_dimension_t<exp<energy, 1>, exp<base_dim_time, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<power>> : std::type_identity<power> {};
|
||||
struct power : derived_dimension<power, exp<energy, 1>, exp<base_dim_time, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Power = QuantityOf<T, power>;
|
||||
|
||||
struct watt : derived_unit<power, kilogram, metre, second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<watt>> : std::type_identity<watt> {};
|
||||
struct watt : derived_unit<watt, power, kilogram, metre, second> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -28,14 +28,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct pressure : make_dimension_t<exp<force, 1>, exp<area, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<pressure>> : std::type_identity<pressure> {};
|
||||
struct pressure : derived_dimension<pressure, exp<force, 1>, exp<area, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Pressure = QuantityOf<T, pressure>;
|
||||
|
||||
struct pascal : derived_unit<pressure, kilogram, metre, second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<pascal>> : std::type_identity<pascal> {};
|
||||
struct pascal : derived_unit<pascal, pressure, kilogram, metre, second> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,14 +27,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct substance : make_dimension_t<exp<base_dim_substance, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<substance>> : std::type_identity<substance> {};
|
||||
struct substance : derived_dimension<substance, exp<base_dim_substance, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Substance = QuantityOf<T, substance>;
|
||||
|
||||
struct mole : unit<substance> {};
|
||||
template<> struct downcast_traits<downcast_base_t<mole>> : std::type_identity<mole> {};
|
||||
struct mole : derived_unit<mole, substance> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,14 +27,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct temperature : make_dimension_t<exp<base_dim_temperature, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<temperature>> : std::type_identity<temperature> {};
|
||||
struct temperature : derived_dimension<temperature, exp<base_dim_temperature, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool ThermodynamicTemperature = QuantityOf<T, temperature>;
|
||||
|
||||
struct kelvin : unit<temperature> {};
|
||||
template<> struct downcast_traits<downcast_base_t<kelvin>> : std::type_identity<kelvin> {};
|
||||
struct kelvin : derived_unit<kelvin, temperature> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,29 +27,17 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct time : make_dimension_t<exp<base_dim_time, 1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<time>> : std::type_identity<time> {};
|
||||
struct time : derived_dimension<time, exp<base_dim_time, 1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Time = QuantityOf<T, time>;
|
||||
|
||||
struct second : unit<time> {};
|
||||
template<> struct downcast_traits<downcast_base_t<second>> : std::type_identity<second> {};
|
||||
|
||||
struct nanosecond : nano<second> {};
|
||||
template<> struct downcast_traits<downcast_base_t<nanosecond>> : std::type_identity<nanosecond> {};
|
||||
|
||||
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> {};
|
||||
struct second : derived_unit<second, time> {};
|
||||
struct nanosecond : derived_unit<nanosecond, nano<second>> {};
|
||||
struct microsecond : derived_unit<microsecond, micro<second>> {};
|
||||
struct millisecond : derived_unit<millisecond, milli<second>> {};
|
||||
struct minute : derived_unit<minute, time, ratio<60>> {};
|
||||
struct hour : derived_unit<hour, time, ratio<3600>> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -27,20 +27,14 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<velocity>> : std::type_identity<velocity> {};
|
||||
struct velocity : derived_dimension<velocity, exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Velocity = QuantityOf<T, velocity>;
|
||||
|
||||
struct metre_per_second : derived_unit<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<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> {};
|
||||
struct metre_per_second : derived_unit<metre_per_second, velocity, metre, 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> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -30,14 +30,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct voltage : make_dimension_t<exp<power, 1>, exp<base_dim_current, -1>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<voltage>> : std::type_identity<voltage> {};
|
||||
struct voltage : derived_dimension<voltage, exp<power, 1>, exp<base_dim_current, -1>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Voltage = QuantityOf<T, voltage>;
|
||||
|
||||
struct volt : derived_unit<voltage, kilogram, metre, second, ampere> {};
|
||||
template<> struct downcast_traits<downcast_base_t<volt>> : std::type_identity<volt> {};
|
||||
struct volt : derived_unit<volt, voltage, kilogram, metre, second, ampere> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -26,26 +26,16 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct volume : make_dimension_t<exp<base_dim_length, 3>> {};
|
||||
template<> struct downcast_traits<downcast_base_t<volume>> : std::type_identity<volume> {};
|
||||
struct volume : derived_dimension<volume, exp<base_dim_length, 3>> {};
|
||||
|
||||
template<typename T>
|
||||
concept bool Volume = QuantityOf<T, volume>;
|
||||
|
||||
struct cubic_millimetre : derived_unit<volume, millimetre> {};
|
||||
template<> struct downcast_traits<downcast_base_t<cubic_millimetre>> : std::type_identity<cubic_millimetre> {};
|
||||
|
||||
struct cubic_centimetre : derived_unit<volume, centimetre> {};
|
||||
template<> struct downcast_traits<downcast_base_t<cubic_centimetre>> : std::type_identity<cubic_centimetre> {};
|
||||
|
||||
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> {};
|
||||
struct cubic_millimetre : derived_unit<cubic_millimetre, volume, millimetre> {};
|
||||
struct cubic_centimetre : derived_unit<cubic_centimetre, volume, centimetre> {};
|
||||
struct cubic_metre : derived_unit<cubic_metre, volume, metre> {};
|
||||
struct cubic_kilometre : derived_unit<cubic_kilometre, volume, kilometre, metre> {};
|
||||
struct cubic_foot : derived_unit<cubic_foot, volume, foot> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@@ -32,7 +32,7 @@ namespace units {
|
||||
{
|
||||
using dim = dimension_pow_t<typename U::dimension, 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>
|
||||
@@ -40,7 +40,7 @@ namespace units {
|
||||
{
|
||||
using dim = dimension_sqrt_t<typename U::dimension>;
|
||||
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
|
||||
|
@@ -71,7 +71,7 @@ namespace units {
|
||||
template<typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
|
||||
requires same_dim<typename U1::dimension, typename U2::dimension>
|
||||
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>>
|
||||
@@ -307,7 +307,7 @@ namespace units {
|
||||
{
|
||||
using dim = dimension_multiply_t<typename U1::dimension, typename U2::dimension>;
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace units {
|
||||
|
||||
using dim = dim_invert_t<typename U::dimension>;
|
||||
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>;
|
||||
return ret(v / den(q).count());
|
||||
}
|
||||
@@ -362,7 +362,7 @@ namespace units {
|
||||
|
||||
using common_rep = decltype(lhs.count() / rhs.count());
|
||||
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());
|
||||
}
|
||||
|
||||
|
@@ -52,8 +52,7 @@ namespace units {
|
||||
std::is_empty_v<T> &&
|
||||
detail::is_unit<downcast_base_t<T>>;
|
||||
|
||||
|
||||
// derived_unit
|
||||
// make_derived_unit
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -109,12 +108,30 @@ namespace units {
|
||||
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>
|
||||
using derived_unit = unit<D, typename detail::derived_ratio<typename D::base_type, Us...>::ratio>;
|
||||
// derived_unit
|
||||
|
||||
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 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>>>;
|
||||
|
@@ -30,13 +30,13 @@ namespace {
|
||||
|
||||
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>
|
||||
concept bool DigitalInformation = units::QuantityOf<T, digital_information>;
|
||||
|
||||
struct bit : units::unit<digital_information> {};
|
||||
struct byte : units::unit<digital_information, units::ratio<8>> {};
|
||||
struct bit : units::derived_unit<bit, digital_information> {};
|
||||
struct byte : units::derived_unit<byte, digital_information, units::ratio<8>> {};
|
||||
|
||||
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 {
|
||||
|
||||
static_assert(1_B == 8_b);
|
||||
@@ -64,24 +60,14 @@ namespace {
|
||||
using namespace units;
|
||||
|
||||
// power spectral density
|
||||
struct power_spectral_density : make_dimension_t<units::exp<voltage, 2>, units::exp<frequency, -1>> {};
|
||||
struct sq_volt_per_hertz : unit<power_spectral_density> {};
|
||||
struct power_spectral_density : derived_dimension<power_spectral_density, units::exp<voltage, 2>, units::exp<frequency, -1>> {};
|
||||
struct sq_volt_per_hertz : derived_unit<sq_volt_per_hertz, power_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
|
||||
//struct volt_per_sq_hertz : derived_unit<amplitude_spectral_density, kilogram, metre, second, ampere> {};
|
||||
struct volt_per_sqrt_hertz : unit<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> {};
|
||||
|
||||
struct volt_per_sqrt_hertz : derived_unit<volt_per_sqrt_hertz, amplitude_spectral_density> {};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@@ -54,23 +54,23 @@ namespace {
|
||||
|
||||
// make_dimension
|
||||
|
||||
static_assert(std::is_same_v<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<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<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<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<d0, 1>>, dimension<exp<d0, 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<detail::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<d1, 1>>, dimension<exp<d1, 2>>>);
|
||||
static_assert(std::is_same_v<detail::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, 2>>, dimension<exp<d1, 3, 2>>>);
|
||||
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<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(
|
||||
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<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<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<d1, -1>>, dimension<exp<d0, 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<detail::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>, exp<d1, -1>>, dimension<>>);
|
||||
|
||||
// dimension_multiply
|
||||
|
||||
|
Reference in New Issue
Block a user