mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-02 03:44:27 +02:00
Downcasting facility refactoring
This commit is contained in:
@@ -157,7 +157,7 @@ helper:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, Exponent... Es>
|
template<typename Child, Exponent... Es>
|
||||||
struct derived_dimension : downcast_helper<Child, typename detail::make_dimension<Es...>::type> {};
|
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<Es...>::type> {};
|
||||||
```
|
```
|
||||||
|
|
||||||
`Child` class template parameter is a part of a CRTP idiom and is used to provide a downcasting facility
|
`Child` class template parameter is a part of a CRTP idiom and is used to provide a downcasting facility
|
||||||
@@ -244,7 +244,7 @@ template:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, fixed_string Symbol, Dimension D, typename PrefixType = no_prefix>
|
template<typename Child, fixed_string Symbol, Dimension D, typename PrefixType = no_prefix>
|
||||||
struct coherent_derived_unit : downcast_helper<Child, unit<D, ratio<1>>> {
|
struct coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
using prefix_type = PrefixType;
|
using prefix_type = PrefixType;
|
||||||
};
|
};
|
||||||
@@ -267,7 +267,7 @@ To create the rest of derived units the following class template can be used:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R>
|
template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R>
|
||||||
struct derived_unit : downcast_helper<Child, unit<D, R>> {
|
struct derived_unit : downcast_child<Child, unit<D, R>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -286,7 +286,7 @@ For example to create a prefixed unit the following may be used:
|
|||||||
```cpp
|
```cpp
|
||||||
template<typename Child, Prefix P, Unit U>
|
template<typename Child, Prefix P, Unit U>
|
||||||
requires requires { U::symbol; }
|
requires requires { U::symbol; }
|
||||||
struct prefixed_derived_unit : downcast_helper<Child, unit<typename U::dimension,
|
struct prefixed_derived_unit : downcast_child<Child, unit<typename U::dimension,
|
||||||
ratio_multiply<typename P::ratio,
|
ratio_multiply<typename P::ratio,
|
||||||
typename U::ratio>>> {
|
typename U::ratio>>> {
|
||||||
static constexpr auto symbol = P::symbol + U::symbol;
|
static constexpr auto symbol = P::symbol + U::symbol;
|
||||||
@@ -298,7 +298,7 @@ where `Prefix` is a concept requiring the instantiation of the following class t
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, typename PrefixType, Ratio R, basic_fixed_string Symbol>
|
template<typename Child, typename PrefixType, Ratio R, basic_fixed_string Symbol>
|
||||||
struct prefix : downcast_helper<Child, detail::prefix_base<PrefixType, R>> {
|
struct prefix : downcast_child<Child, detail::prefix_base<PrefixType, R>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -322,7 +322,7 @@ For the cases where determining the exact ratio is not trivial another helper ca
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us>
|
template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us>
|
||||||
struct deduced_derived_unit : downcast_helper<Child, detail::make_derived_unit<D, U, Us...>> {
|
struct deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -541,20 +541,31 @@ 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 facility provides a type substitution mechanism. It connects a specific primary template
|
When dealing with simple types, aliases can be easily replaced with inheritance:
|
||||||
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>>;
|
|
||||||
```
|
As a result we get strong types. There are however a few issues with such an approach:
|
||||||
|
- generic code getting a child class does not easily know the exact template parameters of
|
||||||
|
the base class
|
||||||
|
- generic code after computing the instantiation of the class template does not know if
|
||||||
|
this is a base class in some hierarchy, and in case it is, it does not know how to
|
||||||
|
replace the base class template instantiation with a derived strong type.
|
||||||
|
|
||||||
|
Downcasting facility provides such a type substitution mechanism. It connects a specific primary
|
||||||
|
template class instantiation with a strong type assigned to it by the user.
|
||||||
|
|
||||||
|
Here is the overview of resulting class hierarchy for our example:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
In the above example `metre` is a downcasting target (child class) and a specific `unit` class
|
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
|
template instantiation 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
|
1 to 1 type substitution mechanism. Only one child class can be created for a specific base class
|
||||||
template instantiation.
|
template instantiation.
|
||||||
|
|
||||||
Downcasting facility is provided through 2 dedicated types, a concept, and a few helper template aliases.
|
Downcasting facility is provided through 2 dedicated types, a concept, and a few helper template
|
||||||
|
aliases.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename BaseType>
|
template<typename BaseType>
|
||||||
@@ -568,7 +579,7 @@ struct downcast_base {
|
|||||||
facility with a `base_type` member type, and provides a declaration of downcasting ADL friendly
|
facility with a `base_type` member type, and provides a declaration of downcasting ADL friendly
|
||||||
(Hidden Friend) entry point member function `downcast_guide`. An important design point is that
|
(Hidden Friend) entry point member function `downcast_guide`. An important design point is that
|
||||||
this function does not return any specific type in its declaration. This non-member function
|
this function does not return any specific type in its declaration. This non-member function
|
||||||
is going to be defined in a child class template `downcast_helper` and will return a target
|
is going to be defined in a child class template `downcast_child` and will return a target
|
||||||
type of the downcasting operation there.
|
type of the downcasting operation there.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -585,24 +596,24 @@ facility.
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Target, Downcastable T>
|
template<typename Target, Downcastable T>
|
||||||
struct downcast_helper : T {
|
struct downcast_child : T {
|
||||||
friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); }
|
friend auto downcast_guide(typename downcast_child::downcast_base) { return Target(); }
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
`units::downcast_helper` is another CRTP class template that provides the implementation of a
|
`units::downcast_child` 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
|
non-member friend function of the `downcast_base` class template which defines the target
|
||||||
type of a downcasting operation. It is used in the following way to define `dimension` and
|
type of a downcasting operation. It is used in the following way to define `dimension` and
|
||||||
`unit` types in the library:
|
`unit` types in the library:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, Exponent... Es>
|
template<typename Child, Exponent... Es>
|
||||||
struct derived_dimension : downcast_helper<Child, detail::make_dimension_t<Es...>> {};
|
struct derived_dimension : downcast_child<Child, detail::make_dimension_t<Es...>> {};
|
||||||
```
|
```
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename Child, fixed_string Symbol, Dimension D>
|
template<typename Child, fixed_string Symbol, Dimension D>
|
||||||
struct derived_unit<Child, Symbol, D, R> : downcast_helper<Child, unit<D, ratio<1>>> {};
|
struct derived_unit<Child, Symbol, D, R> : downcast_child<Child, unit<D, ratio<1>>> {};
|
||||||
```
|
```
|
||||||
|
|
||||||
With such CRTP types the only thing the user has to do to register a new type to the downcasting
|
With such CRTP types the only thing the user has to do to register a new type to the downcasting
|
||||||
@@ -618,18 +629,18 @@ downcasting operation a dedicated template alias is provided:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<Downcastable T>
|
template<Downcastable T>
|
||||||
using downcast_target = decltype(detail::downcast_target_impl<T>());
|
using downcast = decltype(detail::downcast_target_impl<T>());
|
||||||
```
|
```
|
||||||
|
|
||||||
`units::downcast_target` is used to obtain the target type of the downcasting operation registered
|
`units::downcast` is used to obtain the target type of the downcasting operation registered
|
||||||
for a given specialization in a base type.
|
for a given instantiation in a base type.
|
||||||
|
|
||||||
For example to determine a downcasted type of a quantity multiply operation the following can be done:
|
For example to determine a downcasted type of a quantity multiply operation the following can be done:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
using dim = dimension_multiply<typename U1::dimension, typename U2::dimension>;
|
using dim = dimension_multiply<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_target<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
using ret = quantity<downcast<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||||
```
|
```
|
||||||
|
|
||||||
`detail::downcast_target_impl` checks if a downcasting target is registered for the specific base class.
|
`detail::downcast_target_impl` checks if a downcasting target is registered for the specific base class.
|
||||||
|
BIN
doc/downcast_1.png
Normal file
BIN
doc/downcast_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
BIN
doc/downcast_2.png
Normal file
BIN
doc/downcast_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@@ -41,8 +41,8 @@ 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>
|
template<typename Target, Downcastable T>
|
||||||
struct downcast_helper : T {
|
struct downcast_child : T {
|
||||||
friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); }
|
friend auto downcast_guide(typename downcast_child::downcast_base) { return Target(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -53,7 +53,7 @@ namespace units {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr auto downcast_target_impl()
|
constexpr auto downcast_impl()
|
||||||
{
|
{
|
||||||
if constexpr(has_downcast<T>)
|
if constexpr(has_downcast<T>)
|
||||||
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
|
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
|
||||||
@@ -64,7 +64,7 @@ namespace units {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<Downcastable T>
|
template<Downcastable T>
|
||||||
using downcast_target = decltype(detail::downcast_target_impl<T>());
|
using downcast = decltype(detail::downcast_impl<T>());
|
||||||
|
|
||||||
template<Downcastable T>
|
template<Downcastable T>
|
||||||
using downcast_base_t = T::base_type;
|
using downcast_base_t = T::base_type;
|
||||||
|
@@ -48,7 +48,7 @@ namespace units {
|
|||||||
{
|
{
|
||||||
if constexpr(Ratio::num != 1 || Ratio::den != 1) {
|
if constexpr(Ratio::num != 1 || Ratio::den != 1) {
|
||||||
if(!std::same_as<PrefixType, no_prefix>) {
|
if(!std::same_as<PrefixType, no_prefix>) {
|
||||||
using prefix = downcast_target<detail::prefix_base<PrefixType, Ratio>>;
|
using prefix = downcast<detail::prefix_base<PrefixType, Ratio>>;
|
||||||
|
|
||||||
if constexpr(!std::same_as<prefix, prefix_base<PrefixType, Ratio>>) {
|
if constexpr(!std::same_as<prefix, prefix_base<PrefixType, Ratio>>) {
|
||||||
// print as a prefixed unit
|
// print as a prefixed unit
|
||||||
|
@@ -151,7 +151,7 @@ namespace units {
|
|||||||
struct dim_invert_impl;
|
struct dim_invert_impl;
|
||||||
|
|
||||||
template<typename... Es>
|
template<typename... Es>
|
||||||
struct dim_invert_impl<dimension<Es...>> : std::type_identity<downcast_target<dimension<exp_invert<Es>...>>> {};
|
struct dim_invert_impl<dimension<Es...>> : std::type_identity<downcast<dimension<exp_invert<Es>...>>> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ namespace units {
|
|||||||
|
|
||||||
// derived_dimension
|
// derived_dimension
|
||||||
template<typename Child, Exponent... Es>
|
template<typename Child, Exponent... Es>
|
||||||
struct derived_dimension : downcast_helper<Child, typename detail::make_dimension<Es...>::type> {};
|
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<Es...>> {};
|
||||||
|
|
||||||
// merge_dimension
|
// merge_dimension
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -243,7 +243,7 @@ namespace units {
|
|||||||
struct dimension_multiply_impl;
|
struct dimension_multiply_impl;
|
||||||
|
|
||||||
template<typename... E1, typename... E2>
|
template<typename... E1, typename... E2>
|
||||||
struct dimension_multiply_impl<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast_target<merge_dimension<dimension<E1...>, dimension<E2...>>>> {};
|
struct dimension_multiply_impl<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast<merge_dimension<dimension<E1...>, dimension<E2...>>>> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ namespace units {
|
|||||||
struct dimension_sqrt_impl;
|
struct dimension_sqrt_impl;
|
||||||
|
|
||||||
template<typename... Es>
|
template<typename... Es>
|
||||||
struct dimension_sqrt_impl<dimension<Es...>> : std::type_identity<downcast_target<dimension<exp_multiply<Es, 1, 2>...>>> {};
|
struct dimension_sqrt_impl<dimension<Es...>> : std::type_identity<downcast<dimension<exp_multiply<Es, 1, 2>...>>> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ namespace units {
|
|||||||
struct dimension_pow_impl;
|
struct dimension_pow_impl;
|
||||||
|
|
||||||
template<typename... Es, std::size_t N>
|
template<typename... Es, std::size_t N>
|
||||||
struct dimension_pow_impl<dimension<Es...>, N> : std::type_identity<downcast_target<dimension<exp_multiply<Es, N, 1>...>>> {};
|
struct dimension_pow_impl<dimension<Es...>, N> : std::type_identity<downcast<dimension<exp_multiply<Es, N, 1>...>>> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ namespace units {
|
|||||||
{
|
{
|
||||||
using dim = dimension_pow<typename U::dimension, N>;
|
using dim = dimension_pow<typename U::dimension, N>;
|
||||||
using r = ratio_pow<typename U::ratio, N>;
|
using r = ratio_pow<typename U::ratio, N>;
|
||||||
return quantity<downcast_target<unit<dim, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
|
return quantity<downcast<unit<dim, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U, typename Rep>
|
template<typename U, typename Rep>
|
||||||
@@ -47,7 +47,7 @@ namespace units {
|
|||||||
{
|
{
|
||||||
using dim = dimension_sqrt<typename U::dimension>;
|
using dim = dimension_sqrt<typename U::dimension>;
|
||||||
using r = ratio_sqrt<typename U::ratio>;
|
using r = ratio_sqrt<typename U::ratio>;
|
||||||
return quantity<downcast_target<unit<dim, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
|
return quantity<downcast<unit<dim, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
@@ -76,7 +76,7 @@ namespace units {
|
|||||||
requires same_dim<typename U1::dimension, typename U2::dimension>
|
requires same_dim<typename U1::dimension, typename U2::dimension>
|
||||||
struct common_quantity_impl<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> {
|
struct common_quantity_impl<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> {
|
||||||
using type =
|
using type =
|
||||||
quantity<downcast_target<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>,
|
quantity<downcast<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>,
|
||||||
Rep>;
|
Rep>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -291,7 +291,7 @@ namespace units {
|
|||||||
using dim = quantity::unit::dimension;
|
using dim = quantity::unit::dimension;
|
||||||
if constexpr(!detail::is_dimension<dim>) {
|
if constexpr(!detail::is_dimension<dim>) {
|
||||||
// print as a prefix or ratio of a coherent unit symbol defined by the user
|
// print as a prefix or ratio of a coherent unit symbol defined by the user
|
||||||
using coherent_unit = downcast_target<units::unit<dim, units::ratio<1>>>;
|
using coherent_unit = downcast<units::unit<dim, units::ratio<1>>>;
|
||||||
detail::print_prefix_or_ratio<ratio, typename coherent_unit::prefix_type>(os);
|
detail::print_prefix_or_ratio<ratio, typename coherent_unit::prefix_type>(os);
|
||||||
os << coherent_unit::symbol;
|
os << coherent_unit::symbol;
|
||||||
}
|
}
|
||||||
@@ -358,7 +358,7 @@ namespace units {
|
|||||||
{
|
{
|
||||||
using dim = dimension_multiply<typename U1::dimension, typename U2::dimension>;
|
using dim = dimension_multiply<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_target<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
using ret = quantity<downcast<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||||
return ret(lhs.count() * rhs.count());
|
return ret(lhs.count() * rhs.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,9 +370,9 @@ namespace units {
|
|||||||
|
|
||||||
using dim = dim_invert<typename U::dimension>;
|
using dim = dim_invert<typename U::dimension>;
|
||||||
using common_rep = decltype(v / q.count());
|
using common_rep = decltype(v / q.count());
|
||||||
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());
|
||||||
|
using ret = quantity<downcast<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U, typename Rep1, Scalar Rep2>
|
template<typename U, typename Rep1, Scalar Rep2>
|
||||||
@@ -407,7 +407,7 @@ namespace units {
|
|||||||
|
|
||||||
using common_rep = decltype(lhs.count() / rhs.count());
|
using common_rep = decltype(lhs.count() / rhs.count());
|
||||||
using dim = dimension_divide<typename U1::dimension, typename U2::dimension>;
|
using dim = dimension_divide<typename U1::dimension, typename U2::dimension>;
|
||||||
using ret = quantity<downcast_target<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
using ret = quantity<downcast<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||||
return ret(lhs.count() / rhs.count());
|
return ret(lhs.count() / rhs.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ namespace units {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Child, typename PrefixType, Ratio R, basic_fixed_string Symbol>
|
template<typename Child, typename PrefixType, Ratio R, basic_fixed_string Symbol>
|
||||||
struct prefix : downcast_helper<Child, detail::prefix_base<PrefixType, R>> {
|
struct prefix : downcast_child<Child, detail::prefix_base<PrefixType, R>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,25 +150,25 @@ namespace units {
|
|||||||
struct no_prefix;
|
struct no_prefix;
|
||||||
|
|
||||||
template<typename Child, basic_fixed_string Symbol, Dimension D, typename PrefixType = no_prefix>
|
template<typename Child, basic_fixed_string Symbol, Dimension D, typename PrefixType = no_prefix>
|
||||||
struct coherent_derived_unit : downcast_helper<Child, unit<D, ratio<1>>> {
|
struct coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
using prefix_type = PrefixType;
|
using prefix_type = PrefixType;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R>
|
template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R>
|
||||||
struct derived_unit : downcast_helper<Child, unit<D, R>> {
|
struct derived_unit : downcast_child<Child, unit<D, R>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Child, Prefix P, Unit U>
|
template<typename Child, Prefix P, Unit U>
|
||||||
requires requires { U::symbol; }
|
requires requires { U::symbol; }
|
||||||
struct prefixed_derived_unit : downcast_helper<Child, unit<typename U::dimension, ratio_multiply<typename P::ratio, typename U::ratio>>> {
|
struct prefixed_derived_unit : downcast_child<Child, unit<typename U::dimension, ratio_multiply<typename P::ratio, typename U::ratio>>> {
|
||||||
static constexpr auto symbol = P::symbol + U::symbol;
|
static constexpr auto symbol = P::symbol + U::symbol;
|
||||||
using prefix_type = P::prefix_type;
|
using prefix_type = P::prefix_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us>
|
template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us>
|
||||||
struct deduced_derived_unit : downcast_helper<Child, detail::make_derived_unit<D, U, Us...>> {
|
struct deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user