@@ -4150,51 +4150,67 @@ namespace std
41504150// UNIT DEDUCTION GUIDES
41514151// ------------------------------
41524152
4153- namespace units
4154- {
4153+ namespace units {
4154+
4155+ // Concept to ensure we only apply the dimensionless fallback
4156+ // to a pure, unmodified dimensionless unit.
4157+ template <class Cf >
4158+ concept PureDimensionlessCF =
4159+ std::is_same_v<typename Cf::dimension_type, dimension::dimensionless> &&
4160+ std::ratio_equal_v<typename Cf::conversion_ratio, std::ratio<1 >> &&
4161+ std::ratio_equal_v<typename Cf::pi_exponent_ratio, std::ratio<0 >> &&
4162+ std::ratio_equal_v<typename Cf::translation_ratio, std::ratio<0 >>;
4163+
41554164 // 1) chrono deduction guide
41564165 template <ArithmeticType Rep, RatioType Period>
4157- unit (std::chrono::duration<Rep, Period>)
4158- -> unit<conversion_factor<Period, dimension::time>, Rep>;
4166+ unit (std::chrono::duration<Rep, Period>) -> unit<conversion_factor<Period, dimension::time>, Rep>;
41594167
41604168 // 2) Dimensionless fallback:
4161- // Now restricted to apply only if the source is exactly the base dimensionless unit,
4162- // i.e. conversion_factor<std::ratio<1>, dimension::dimensionless> with no pi exponent or translation.
4169+ // Only applies if the source is exactly the base dimensionless unit.
41634170 template <ArithmeticType SourceTy, ConversionFactorType SourceCf>
4164- requires (
4165- traits::is_unit_v<unit<SourceCf, SourceTy>> &&
4166- std::is_same_v<typename SourceCf::dimension_type, dimension::dimensionless> &&
4167- // Ensuring it's the pure base dimensionless factor:
4168- std::ratio_equal<typename SourceCf::conversion_ratio, std::ratio<1 >>::value &&
4169- std::ratio_equal<typename SourceCf::pi_exponent_ratio, std::ratio<0 >>::value &&
4170- std::ratio_equal<typename SourceCf::translation_ratio, std::ratio<0 >>::value
4171- )
4172- unit (const unit<SourceCf, SourceTy>&)
4173- -> unit<conversion_factor<std::ratio<1 >, dimension::dimensionless>, SourceTy>;
4174-
4175- // 3) General conversion factor from Target, type from Source:
4176- // Applies only if TargetCf differs from SourceCf and they share the same dimension.
4171+ requires (
4172+ traits::is_unit_v<unit<SourceCf, SourceTy>> &&
4173+ PureDimensionlessCF<SourceCf>
4174+ )
4175+ unit (const unit<SourceCf, SourceTy>&) -> unit<conversion_factor<std::ratio<1 >, dimension::dimensionless>, SourceTy>;
4176+
4177+ // 3) Lossless integral conversion:
4178+ // For dimensionally compatible units where the conversion is integral and lossless.
4179+ // This applies only if is_losslessly_convertible_unit is true.
41774180 template <ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
4178- requires (
4179- traits::is_unit_v<unit<SourceCf, SourceTy>> &&
4180- traits::is_conversion_factor_v<TargetCf> &&
4181- traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
4182- !std::is_same_v<SourceCf, TargetCf>
4183- )
4181+ requires (
4182+ traits::is_unit_v<unit<SourceCf, SourceTy>> &&
4183+ traits::is_conversion_factor_v<TargetCf> &&
4184+ traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
4185+ !std::is_same_v<SourceCf, TargetCf> &&
4186+ detail::is_losslessly_convertible_unit<unit<SourceCf, SourceTy>, unit<TargetCf, SourceTy>>
4187+ )
41844188 unit (const unit<SourceCf, SourceTy>&) -> unit<TargetCf, SourceTy>;
41854189
4186- // 4) Matching Target and Source factors exactly
4190+ // 4) Non-lossless conversions:
4191+ // For dimensionally compatible units where integral conversion is not possible.
4192+ // Falls back to floating point.
4193+ template <ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
4194+ requires (
4195+ traits::is_unit_v<unit<SourceCf, SourceTy>> &&
4196+ traits::is_conversion_factor_v<TargetCf> &&
4197+ traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
4198+ !std::is_same_v<SourceCf, TargetCf> &&
4199+ !detail::is_losslessly_convertible_unit<unit<SourceCf, SourceTy>, unit<TargetCf, SourceTy>>
4200+ )
4201+ unit (const unit<SourceCf, SourceTy>&) -> unit<TargetCf, detail::floating_point_promotion_t <SourceTy>>;
4202+
4203+ // 5) Exact matches:
4204+ // If the unit already matches `unit<TargetCf, SourceTy>`, use it directly.
41874205 template <ConversionFactorType TargetCf, ArithmeticType SourceTy>
4188- requires traits::is_unit_v<unit<TargetCf, SourceTy>>
4206+ requires traits::is_unit_v<unit<TargetCf, SourceTy>>
41894207 unit (const unit<TargetCf, SourceTy>&) -> unit<TargetCf, SourceTy>;
41904208
4191- // 5) Deduce type from arithmetic type (dimensionless by default)
4192- template <typename T,
4193- typename Cf = dimension::dimensionless,
4194- typename = std::enable_if_t <std::is_arithmetic_v<T>>>
4209+ // 6) Deduce type from arithmetic type (dimensionless by default)
4210+ template <typename T, typename Cf = dimension::dimensionless, typename = std::enable_if_t <std::is_arithmetic_v<T>>>
41954211 unit (T) -> unit<Cf, T>;
4196- } // namespace units
41974212
4213+ } // namespace units
41984214
41994215
42004216// ----------------------------------------------------------------------------------------------------------------------
0 commit comments