Downcasting reworked to allow OFF and AUTO modes

This commit is contained in:
Mateusz Pusz
2020-08-19 13:37:57 +02:00
parent 12c0177633
commit 5c98924efb
24 changed files with 386 additions and 216 deletions
+6 -11
View File
@@ -23,15 +23,11 @@
#pragma once
#include <units/bits/dimension_op.h>
#include <units/bits/equivalent.h>
#include <units/quantity_cast.h>
namespace units {
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity;
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity_point;
namespace detail {
template<typename Q1, typename Q2, typename Rep>
@@ -55,9 +51,8 @@ struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep>
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
static constexpr ratio r1 = D1::base_units_ratio * U1::ratio;
static constexpr ratio r2 = D2::base_units_ratio * U2::ratio;
using type = quantity<D1, downcast_unit<D1, common_ratio(r1, r2)>, Rep>;
using dimension = conditional<is_instantiation_of<D1, unknown_dimension>, D2, D1>;
using type = quantity<dimension, downcast_unit<dimension, common_ratio(U1::ratio, U2::ratio)>, Rep>;
};
template<typename D, typename U, typename Rep>
@@ -66,7 +61,7 @@ quantity_point<D, U, Rep> common_quantity_point_impl(quantity<D, U, Rep>);
} // namespace detail
template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
requires equivalent_dim<typename Q1::dimension, typename Q2::dimension>
requires equivalent<typename Q1::dimension, typename Q2::dimension>
using common_quantity = detail::common_quantity_impl<Q1, Q2, Rep>::type;
template<QuantityPoint QP1, QuantityPoint QP2>
@@ -87,7 +82,7 @@ namespace concepts {
#endif
template<units::Quantity Q1, units::Quantity Q2>
requires units::equivalent_dim<typename Q1::dimension, typename Q2::dimension>
requires units::equivalent<typename Q1::dimension, typename Q2::dimension>
struct common_type<Q1, Q2> {
using type = units::common_quantity<Q1, Q2>;
};
+1 -37
View File
@@ -27,40 +27,6 @@
namespace units {
// equivalent_dim
namespace detail {
template<BaseDimension D1, BaseDimension D2>
using equivalent_base_dim = std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
same_unit_reference<typename D1::base_unit, typename D2::base_unit>>;
template<Dimension D1, Dimension D2>
struct equivalent_dim_impl : std::false_type {};
template<BaseDimension D1, BaseDimension D2>
struct equivalent_dim_impl<D1, D2> : std::disjunction<is_same<D1, D2>, equivalent_base_dim<D1, D2>> {};
template<Exponent E1, Exponent E2>
struct equivalent_exp : std::false_type {};
template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2>
struct equivalent_exp<exp<Dim1, Num, Den>, exp<Dim2, Num, Den>> : equivalent_dim_impl<Dim1, Dim2> {};
template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_derived_dim : std::false_type {};
template<typename... Es1, typename... Es2>
requires (sizeof...(Es1) == sizeof...(Es2))
struct equivalent_derived_dim<derived_dimension_base<Es1...>, derived_dimension_base<Es2...>> : std::conjunction<equivalent_exp<Es1, Es2>...> {};
template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_dim_impl<D1, D2> : std::disjunction<is_same<D1, D2>, equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {};
} // namespace detail
template<Dimension D1, Dimension D2>
inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::value;
/**
* @brief Unknown dimension
*
@@ -72,9 +38,7 @@ inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::valu
* @tparam ERest the list of exponents of ingredient dimensions
*/
template<Exponent E, Exponent... ERest>
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, scaled_unit<ratio(1), unknown_coherent_unit>, E, ERest...> {
using coherent_unit = scaled_unit<ratio(1), unknown_coherent_unit>;
};
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, unknown_coherent_unit, E, ERest...> {};
namespace detail {
+98
View File
@@ -0,0 +1,98 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/concepts.h>
#include <units/unit.h>
namespace units {
namespace detail {
template<typename T, typename U>
struct equivalent_impl : std::false_type {
};
// units
template<Unit U1, Unit U2>
struct equivalent_impl<U1, U2> : std::disjunction<std::is_same<U1, U2>, std::is_base_of<U1, U2>, std::is_base_of<U2, U1>> {};
// dimensions
template<BaseDimension D1, BaseDimension D2>
struct equivalent_base_dim :
std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
same_unit_reference<typename D1::base_unit, typename D2::base_unit>> {
};
template<BaseDimension D1, BaseDimension D2>
struct equivalent_impl<D1, D2> : std::disjunction<std::is_same<D1, D2>, equivalent_base_dim<D1, D2>> {
};
template<Exponent E1, Exponent E2>
struct equivalent_exp : std::false_type {
};
template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2>
struct equivalent_exp<exp<Dim1, Num, Den>, exp<Dim2, Num, Den>> : equivalent_impl<Dim1, Dim2> {
};
template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_derived_dim : std::false_type {
};
template<typename... Es1, typename... Es2>
requires(sizeof...(Es1) == sizeof...(Es2))
struct equivalent_derived_dim<derived_dimension_base<Es1...>, derived_dimension_base<Es2...>> :
std::conjunction<equivalent_exp<Es1, Es2>...> {
};
template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_impl<D1, D2> :
std::disjunction<std::is_same<D1, D2>, std::is_base_of<D1, D2>, std::is_base_of<D2, D1>,
equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {
};
// additionally accounts for unknown dimensions
template<Unit U1, Dimension D1, Unit U2, Dimension D2>
struct equivalent_unit : std::disjunction<equivalent_impl<U1, U2>,
std::bool_constant<U1::ratio / dimension_unit<D1>::ratio == U2::ratio / dimension_unit<D2>::ratio>> {};
// quantities and quantity points
template<typename Q1, typename Q2>
requires (Quantity<Q1> && Quantity<Q2>) || (QuantityPoint<Q1> && QuantityPoint<Q2>)
struct equivalent_impl<Q1, Q2> : std::disjunction<std::is_same<Q1, Q2>,
std::conjunction<equivalent_impl<typename Q1::dimension, typename Q2::dimension>,
equivalent_unit<typename Q1::unit, typename Q1::dimension,
typename Q2::unit, typename Q2::dimension>>> {};
} // namespace detail
template<typename T, typename U>
inline constexpr bool equivalent = detail::equivalent_impl<T, U>::value;
} // namespace units
+44 -13
View File
@@ -25,44 +25,75 @@
#include <units/bits/external/hacks.h>
#include <type_traits>
#ifdef DOWNCAST_MODE
#if DOWNCAST_MODE < 0 || DOWNCAST_MODE > 2
#error "Invalid DOWNCAST_MODE value"
#endif
#else
#define DOWNCAST_MODE 2
#endif
namespace units {
template<typename BaseType>
struct downcast_base {
using downcast_base_type = BaseType;
friend auto downcast_guide(downcast_base);
friend auto downcast_poison_pill(downcast_base);
};
template<typename T>
concept Downcastable =
requires {
typename T::downcast_base_type;
} &&
requires { typename T::downcast_base_type; } &&
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
template<typename Target, Downcastable T>
struct downcast_child : T {
friend auto downcast_guide(typename downcast_child::downcast_base /* base */) { return Target(); }
};
namespace detail {
template<typename T>
concept has_downcast =
concept has_downcast_guide =
requires {
downcast_guide(std::declval<downcast_base<T>>());
};
template<typename T>
concept has_downcast_poison_pill =
requires {
downcast_poison_pill(std::declval<downcast_base<T>>());
};
template<typename Target, Downcastable T>
struct downcast_child : T {
friend auto downcast_guide(typename T::downcast_base)
{ return Target(); }
};
template<Downcastable T>
struct downcast_poison : T {
friend auto downcast_poison_pill(typename T::downcast_base)
{ return true; }
};
enum class downcast_mode {
off = 0, // no downcasting at all
on = 1, // downcasting always forced -> compile-time errors in case of duplicated definitions
automatic = 2 // downcasting automatically enabled if no collisions are present
};
template<typename Target, Downcastable T, downcast_mode mode = static_cast<downcast_mode>(DOWNCAST_MODE)>
struct downcast_dispatch : std::conditional_t<mode == downcast_mode::off, T,
std::conditional_t<mode == downcast_mode::automatic && has_downcast_guide<T>,
downcast_poison<T>, downcast_child<Target, T>>> {};
namespace detail {
template<typename T>
constexpr auto downcast_impl()
{
if constexpr (has_downcast<T>)
if constexpr(has_downcast_guide<T> && !has_downcast_poison_pill<T>)
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
else
return T();
}
} // namespace detail
}
template<Downcastable T>
using downcast = decltype(detail::downcast_impl<T>());
+1 -1
View File
@@ -79,7 +79,7 @@ using make_dimension = to_derived_dimension_base<typename dim_consolidate<type_l
* @tparam ERest the list of exponents of ingredient dimensions
*/
template<typename Child, Unit U, Exponent E, Exponent... ERest>
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<E, ERest...>> {
struct derived_dimension : downcast_dispatch<Child, typename detail::make_dimension<E, ERest...>> {
using recipe = exp_list<E, ERest...>;
using coherent_unit = U;
static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents());
+1 -1
View File
@@ -70,7 +70,7 @@ struct prefix_base : downcast_base<prefix_base<PF, R>> {
*/
template<typename Child, PrefixFamily PF, basic_symbol_text Symbol, ratio R>
requires (!std::same_as<PF, no_prefix>)
struct prefix : downcast_child<Child, detail::prefix_base<PF, R>> {
struct prefix : downcast_dispatch<Child, detail::prefix_base<PF, R>, downcast_mode::on> {
static constexpr auto symbol = Symbol;
};
+16 -16
View File
@@ -43,10 +43,10 @@ concept safe_convertible = // exposition only
std::convertible_to<From, To> &&
(treat_as_floating_point<To> || (!treat_as_floating_point<From>));
template<typename Rep, typename UnitFrom, typename UnitTo>
template<typename Rep, typename QuantityFrom, typename QuantityTo>
concept safe_divisible = // exposition only
treat_as_floating_point<Rep> ||
is_integral(UnitFrom::ratio / UnitTo::ratio);
is_integral(quantity_ratio(QuantityFrom{}) / quantity_ratio(QuantityTo{}));
} // namespace detail
@@ -78,9 +78,9 @@ public:
constexpr explicit quantity(const Value& v) : value_{static_cast<rep>(v)} {}
template<Quantity Q2>
requires equivalent_dim<D, typename Q2::dimension> &&
requires equivalent<D, typename Q2::dimension> &&
detail::safe_convertible<typename Q2::rep, rep> &&
detail::safe_divisible<rep, typename Q2::unit, unit>
detail::safe_divisible<rep, Q2, quantity>
constexpr quantity(const Q2& q) : value_{quantity_cast<quantity>(q).count()} {}
quantity& operator=(const quantity&) = default;
@@ -223,7 +223,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::three_way_comparable_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
@@ -232,7 +232,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::equality_comparable_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
@@ -243,7 +243,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::equality_comparable_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
@@ -252,7 +252,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator!=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::equality_comparable_with<Rep, Rep2>
{
return !(lhs == rhs);
@@ -260,7 +260,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator<(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
@@ -269,7 +269,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator<=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
return !(rhs < lhs);
@@ -277,7 +277,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
return rhs < lhs;
@@ -285,7 +285,7 @@ public:
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator>=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
requires equivalent<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
return !(lhs < rhs);
@@ -337,14 +337,14 @@ template<Scalar Value, typename D, typename U, typename Rep>
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::multiplies<>, Rep1, Rep2> &&
equivalent_dim<D1, dim_invert<D2>>
equivalent<D1, dim_invert<D2>>
{
using common_rep = decltype(lhs.count() * rhs.count());
const ratio r = U1::ratio * U2::ratio;
if constexpr (treat_as_floating_point<common_rep>) {
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
} else {
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * ipow10(r.exp)) / static_cast<common_rep>(r.den);
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::ipow10(r.exp)) / static_cast<common_rep>(r.den);
}
}
@@ -386,7 +386,7 @@ template<typename D, typename U, typename Rep, Scalar Value>
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::divides<>, Rep1, Rep2> &&
equivalent_dim<D1, D2>
equivalent<D1, D2>
{
Expects(rhs.count() != 0);
+26 -13
View File
@@ -30,6 +30,14 @@
namespace units {
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity;
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity_point;
namespace detail {
constexpr std::intmax_t ipow10(std::intmax_t exp)
{
assert(exp >= 0);
@@ -61,10 +69,22 @@ constexpr Rep fpow10(std::intmax_t exp)
return result;
}
template<typename D, typename U, typename Rep>
constexpr auto quantity_ratio(const quantity<D, U, Rep>&)
{
if constexpr(BaseDimension<D>) {
return U::ratio;
}
else {
return D::base_units_ratio * U::ratio / D::coherent_unit::ratio;
}
}
} // namespace detail
// QuantityOf
template<typename T, typename Dim>
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent_dim<typename T::dimension, Dim>;
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent<typename T::dimension, Dim>;
// quantity_cast
namespace detail {
@@ -290,17 +310,10 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
}
};
template<Dimension FromD, Unit FromU, Dimension ToD, Unit ToU>
constexpr ratio cast_ratio()
template<typename Q1, typename Q2>
constexpr ratio cast_ratio(const Q1& from, const Q2& to)
{
if constexpr(BaseDimension<FromD> || same_unit_reference<FromU, ToU>::value) {
return FromU::ratio / ToU::ratio;
}
else {
const ratio from_ratio = FromD::base_units_ratio * FromU::ratio;
const ratio to_ratio = ToD::base_units_ratio * ToU::ratio;
return from_ratio / to_ratio;
}
return quantity_ratio(from) / quantity_ratio(to);
}
} // namespace detail
@@ -321,7 +334,7 @@ template<Quantity To, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires QuantityOf<To, D>
{
using c_ratio = std::integral_constant<ratio, detail::cast_ratio<D, U, typename To::dimension, typename To::unit>()>;
using c_ratio = std::integral_constant<ratio, detail::cast_ratio(quantity<D, U, Rep>(), To())>;
using c_rep = std::common_type_t<typename To::rep, Rep>;
using ret_unit = downcast_unit<typename To::dimension, To::unit::ratio>;
using ret = quantity<typename To::dimension, ret_unit, typename To::rep>;
@@ -343,7 +356,7 @@ template<Quantity To, typename D, typename U, typename Rep>
*/
template<Dimension ToD, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires equivalent_dim<ToD, D>
requires equivalent<ToD, D>
{
return quantity_cast<quantity<ToD, dimension_unit<ToD>, Rep>>(q);
}
+14 -14
View File
@@ -74,18 +74,11 @@ struct same_unit_reference : is_same<typename U1::reference, typename U2::refere
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
*/
template<typename Child>
struct unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
struct unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
static constexpr bool is_named = false;
using prefix_family = no_prefix;
};
/**
* @brief Unknown unit
*
* Used as a coherent unit of an unknown dimension.
*/
struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
/**
* @brief A named unit
*
@@ -99,7 +92,7 @@ struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
* @tparam PF no_prefix or a type of prefix family
*/
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF>
struct named_unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
struct named_unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_family = PF;
@@ -121,7 +114,7 @@ struct named_unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
*/
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF, ratio R, Unit U>
requires UnitRatio<R>
struct named_scaled_unit : downcast_child<Child, scaled_unit<R * U::ratio, typename U::reference>> {
struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<R * U::ratio, typename U::reference>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_family = PF;
@@ -140,7 +133,7 @@ struct named_scaled_unit : downcast_child<Child, scaled_unit<R * U::ratio, typen
*/
template<typename Child, Prefix P, Unit U>
requires U::is_named && std::same_as<typename P::prefix_family, typename U::prefix_family>
struct prefixed_unit : downcast_child<Child, scaled_unit<P::ratio * U::ratio, typename U::reference>> {
struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::ratio * U::ratio, typename U::reference>> {
static constexpr bool is_named = true;
static constexpr auto symbol = P::symbol + U::symbol;
using prefix_family = no_prefix;
@@ -162,7 +155,7 @@ struct prefixed_unit : downcast_child<Child, scaled_unit<P::ratio * U::ratio, ty
template<typename Child, DerivedDimension Dim, Unit U, Unit... URest>
requires detail::same_scaled_units<typename Dim::recipe, U, URest...> &&
(U::is_named && (URest::is_named && ... && true))
struct deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
struct deduced_unit : downcast_dispatch<Child, detail::deduced_unit<Dim, U, URest...>> {
static constexpr bool is_named = false;
static constexpr auto symbol = detail::deduced_symbol_text<Dim, U, URest...>();
using prefix_family = no_prefix;
@@ -186,7 +179,7 @@ template<typename Child, DerivedDimension Dim, Unit U, Unit... URest>
requires detail::same_scaled_units<typename Dim::recipe, U, URest...> &&
(U::is_named && (URest::is_named && ... && true))
// TODO - 'noble' is placeholder to sort of mean can pass its name on to other deduced units
struct noble_deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
struct noble_deduced_unit : downcast_dispatch<Child, detail::deduced_unit<Dim, U, URest...>> {
static constexpr bool is_named = true;
static constexpr auto symbol = detail::deduced_symbol_text<Dim, U, URest...>();
using prefix_family = no_prefix;
@@ -210,7 +203,7 @@ struct noble_deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, U
*/
template<typename Child, DerivedDimension Dim, basic_symbol_text Symbol, PrefixFamily PF, Unit U, Unit... URest>
requires detail::same_scaled_units<typename Dim::recipe, U, URest...>
struct named_deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
struct named_deduced_unit : downcast_dispatch<Child, detail::deduced_unit<Dim, U, URest...>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_family = PF;
@@ -259,4 +252,11 @@ struct prefixed_alias_unit : U {
using prefix_family = no_prefix;
};
/**
* @brief Unknown unit
*
* Used as a coherent unit of an unknown dimension.
*/
struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
} // namespace units