diff --git a/src/core/include/mp-units/framework/unit.h b/src/core/include/mp-units/framework/unit.h index c8ea6a98..7d5a7f07 100644 --- a/src/core/include/mp-units/framework/unit.h +++ b/src/core/include/mp-units/framework/unit.h @@ -62,6 +62,13 @@ struct propagate_point_origin { static constexpr auto point_origin = U::point_origin; }; +template +struct scaled_unit_impl : detail::propagate_point_origin { + using _base_type_ = scaled_unit_impl; // exposition only + static constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(Magnitude) auto mag = M; + static constexpr U reference_unit{}; +}; + } // namespace detail /** @@ -74,10 +81,7 @@ struct propagate_point_origin { * instantiate this type automatically based on the unit arithmetic equation provided by the user. */ template -struct scaled_unit : detail::propagate_point_origin { - static constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(Magnitude) auto mag = M; - static constexpr U reference_unit{}; -}; +struct scaled_unit final : detail::scaled_unit_impl {}; namespace detail { @@ -137,6 +141,7 @@ struct named_unit; template requires(!Symbol.empty()) && detail::BaseDimension> struct named_unit { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique base unit identifier static constexpr auto quantity_spec = QS; }; @@ -144,6 +149,7 @@ struct named_unit { template requires(!Symbol.empty()) && detail::BaseDimension> struct named_unit { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique base unit identifier static constexpr auto quantity_spec = QS; static constexpr auto point_origin = PO; @@ -162,6 +168,7 @@ struct named_unit { template requires(!Symbol.empty()) struct named_unit { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique base unit identifier }; @@ -175,13 +182,15 @@ struct named_unit { */ template requires(!Symbol.empty()) -struct named_unit : decltype(U) { +struct named_unit : decltype(U)::_base_type_ { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique unit identifier }; template requires(!Symbol.empty()) -struct named_unit : decltype(U) { +struct named_unit : decltype(U)::_base_type_ { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique unit identifier static constexpr auto point_origin = PO; }; @@ -197,14 +206,16 @@ struct named_unit : decltype(U) { */ template requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension) -struct named_unit : decltype(U) { +struct named_unit : decltype(U)::_base_type_ { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique unit identifier static constexpr auto quantity_spec = QS; }; template requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension) -struct named_unit : decltype(U) { +struct named_unit : decltype(U)::_base_type_ { + using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique unit identifier static constexpr auto quantity_spec = QS; static constexpr auto point_origin = PO; @@ -234,7 +245,8 @@ struct named_unit : decltype(U) { */ MP_UNITS_EXPORT template requires(!Symbol.empty()) -struct prefixed_unit : decltype(M * U) { +struct prefixed_unit : decltype(M * U)::_base_type_ { + using _base_type_ = prefixed_unit; // exposition only static constexpr auto symbol = Symbol + U.symbol; }; @@ -243,6 +255,11 @@ namespace detail { template struct is_one : std::false_type {}; +template +struct derived_unit_impl : detail::expr_fractions { + using _base_type_ = derived_unit_impl; // exposition only +}; + } // namespace detail /** @@ -291,7 +308,7 @@ struct is_one : std::false_type {}; * instantiate this type automatically based on the unit arithmetic equation provided by the user. */ template -struct derived_unit : detail::expr_fractions {}; +struct derived_unit : detail::derived_unit_impl {}; /** * @brief Unit one @@ -299,7 +316,7 @@ struct derived_unit : detail::expr_fractions {}; * Unit of a dimensionless quantity. */ // clang-format off -MP_UNITS_EXPORT inline constexpr struct one : derived_unit<> {} one; +MP_UNITS_EXPORT inline constexpr struct one : detail::derived_unit_impl<> {} one; // clang-format on namespace detail { @@ -337,10 +354,10 @@ template [[nodiscard]] consteval auto get_canonical_unit_impl(T, const power&); template -[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit&); +[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit_impl&); template -[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit&) +[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit_impl&) { using base = decltype(get_canonical_unit_impl(U{}, U{})); return canonical_unit{}; @@ -392,10 +409,10 @@ template } template -[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit&) +[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit_impl&) { - using num = decltype(get_canonical_unit_impl(typename derived_unit::_num_{})); - using den = decltype(get_canonical_unit_impl(typename derived_unit::_den_{})); + using num = decltype(get_canonical_unit_impl(typename derived_unit_impl::_num_{})); + using den = decltype(get_canonical_unit_impl(typename derived_unit_impl::_den_{})); return canonical_unit{}; } @@ -599,9 +616,9 @@ template requires(decltype(detail::have_same_canonical_reference_unit(u1, u2))::value) { if constexpr (U1{} == U2{}) { - if constexpr (std::derived_from) + if constexpr (std::derived_from) return u1; - else if constexpr (std::derived_from) + else if constexpr (std::derived_from) return u2; else // TODO Check if there is a better choice here @@ -695,7 +712,7 @@ constexpr Out unit_symbol_impl(Out out, U, const unit_symbol_formatting& fmt, bo } template Out, auto M, typename U> -constexpr Out unit_symbol_impl(Out out, const scaled_unit& u, const unit_symbol_formatting& fmt, +constexpr Out unit_symbol_impl(Out out, const scaled_unit_impl& u, const unit_symbol_formatting& fmt, bool negative_power) { if constexpr (M == mag<1>) { @@ -764,13 +781,13 @@ constexpr Out unit_symbol_impl(Out out, const type_list& nums, const ty } template Out, typename... Expr> -constexpr Out unit_symbol_impl(Out out, const derived_unit&, const unit_symbol_formatting& fmt, +constexpr Out unit_symbol_impl(Out out, const derived_unit_impl&, const unit_symbol_formatting& fmt, bool negative_power) { (void)negative_power; MP_UNITS_EXPECTS(negative_power == false); - return unit_symbol_impl(out, typename derived_unit::_num_{}, typename derived_unit::_den_{}, - fmt); + return unit_symbol_impl(out, typename derived_unit_impl::_num_{}, + typename derived_unit_impl::_den_{}, fmt); } } // namespace detail diff --git a/src/core/include/mp-units/framework/unit_concepts.h b/src/core/include/mp-units/framework/unit_concepts.h index bd42dc27..cbc9abf3 100644 --- a/src/core/include/mp-units/framework/unit_concepts.h +++ b/src/core/include/mp-units/framework/unit_concepts.h @@ -52,6 +52,8 @@ struct scaled_unit; MP_UNITS_EXPORT template struct named_unit; +MP_UNITS_EXPORT struct one; + namespace detail { template @@ -126,9 +128,14 @@ void is_unit_impl(const scaled_unit*); template void is_unit_impl(const named_unit*); +template +void is_unit_impl(const prefixed_unit*); + template void is_unit_impl(const derived_unit*); +void is_unit_impl(const one*); + template inline constexpr bool is_specialization_of_unit = false; diff --git a/test/static/concepts_test.cpp b/test/static/concepts_test.cpp index 85e5a58c..33fd85a5 100644 --- a/test/static/concepts_test.cpp +++ b/test/static/concepts_test.cpp @@ -138,8 +138,6 @@ static_assert(!detail::QuantityKindSpec); // TODO add tests // Unit -struct metre_per_second : decltype(si::metre / si::second) {}; - static_assert(Unit); static_assert(Unit); static_assert(Unit)>); @@ -151,13 +149,12 @@ static_assert(Unit); static_assert(Unit(si::metre))>); static_assert(Unit); static_assert(Unit, struct si::second>>); -static_assert(Unit); static_assert(Unit>>); static_assert(Unit); -static_assert(!Unit>); +static_assert(!Unit>>); static_assert(!Unit>); static_assert(!Unit>); -static_assert(!Unit>); +static_assert(!Unit>>); static_assert(!Unit, si::second>>); static_assert(!Unit); static_assert(!Unit); @@ -177,13 +174,12 @@ static_assert(!detail::NamedUnit); static_assert(!detail::NamedUnit(si::metre))>); static_assert(detail::NamedUnit); static_assert(!detail::NamedUnit, struct si::second>>); -static_assert(!detail::NamedUnit); static_assert(!detail::NamedUnit>>); static_assert(!detail::NamedUnit); -static_assert(!detail::NamedUnit>); +static_assert(!detail::NamedUnit>>); static_assert(!detail::NamedUnit>); static_assert(!detail::NamedUnit>); -static_assert(!detail::NamedUnit>); +static_assert(!detail::NamedUnit>>); static_assert(!detail::NamedUnit, si::second>>); static_assert(!detail::NamedUnit); static_assert(!detail::NamedUnit); @@ -203,13 +199,12 @@ static_assert(!PrefixableUnit); static_assert(!PrefixableUnit(si::metre))>); static_assert(PrefixableUnit); static_assert(!PrefixableUnit, struct si::second>>); -static_assert(!PrefixableUnit); static_assert(!PrefixableUnit>>); static_assert(!PrefixableUnit); -static_assert(!PrefixableUnit>); +static_assert(!PrefixableUnit>>); static_assert(!PrefixableUnit>); static_assert(!PrefixableUnit>); -static_assert(!PrefixableUnit>); +static_assert(!PrefixableUnit>>); static_assert(!PrefixableUnit, si::second>>); static_assert(!PrefixableUnit); static_assert(!PrefixableUnit); @@ -229,13 +224,12 @@ static_assert(AssociatedUnit); static_assert(AssociatedUnit(si::metre))>); static_assert(AssociatedUnit); static_assert(AssociatedUnit, struct si::second>>); -static_assert(AssociatedUnit); static_assert(AssociatedUnit>>); static_assert(AssociatedUnit); -static_assert(!AssociatedUnit>); +static_assert(!AssociatedUnit>>); static_assert(!AssociatedUnit>); static_assert(!AssociatedUnit>); -static_assert(!AssociatedUnit>); +static_assert(!AssociatedUnit>>); static_assert(!AssociatedUnit, si::second>>); static_assert(!AssociatedUnit); static_assert(!AssociatedUnit); diff --git a/test/static/reference_test.cpp b/test/static/reference_test.cpp index df928505..58e2611d 100644 --- a/test/static/reference_test.cpp +++ b/test/static/reference_test.cpp @@ -192,7 +192,7 @@ static_assert(is_of_type<2 * m_per_s, quantity>, derived_unit>>{}, int>>); + quantity>, derived_unit)>, per>>{}, int>>); static_assert(120 * length[kilometre] / (2 * time[hour]) == 60 * speed[kilometre / hour]); static_assert( is_of_type< @@ -201,14 +201,14 @@ static_assert( const auto duration = 2; return distance * length[kilometre] / (duration * time[hour]); }(), - quantity>, derived_unit>>{}, int>>); + quantity>, derived_unit)>, per>>{}, int>>); static_assert( is_of_type>, derived_unit>>{}, + quantity>, derived_unit)>, per>>{}, std::int64_t>>); static_assert( is_of_type<120.L * length[kilometre] / (2 * time[hour]), - quantity>, derived_unit>>{}, + quantity>, derived_unit)>, per>>{}, long double>>); static_assert(is_of_type<1. / 4 * area[square(metre)], decltype(1. * area[square(metre)] / 4)>); @@ -226,7 +226,7 @@ static_assert(is_of_type<42 * nu::length[nu::second] / (42 * nu::time[nu::second static_assert(is_of_type<42 * nu::speed[nu::second / nu::second], quantity{}, int>>); static_assert(is_of_type<42 * nu::speed[one], quantity{}, int>>); static_assert(is_of_type<42 * mass[kilogram] * (1 * nu::length[nu::second]) / (1 * nu::time[nu::second]), - quantity>, kilogram_>{}, int>>); + quantity>, std::remove_const_t)>>{}, int>>); template concept invalid_nu_unit = !requires { dim[unit]; };