@@ -4150,51 +4150,67 @@ namespace std
4150
4150
// UNIT DEDUCTION GUIDES
4151
4151
// ------------------------------
4152
4152
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
+
4155
4164
// 1) chrono deduction guide
4156
4165
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>;
4159
4167
4160
4168
// 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.
4163
4170
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.
4177
4180
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
+ )
4184
4188
unit (const unit<SourceCf, SourceTy>&) -> unit<TargetCf, SourceTy>;
4185
4189
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.
4187
4205
template <ConversionFactorType TargetCf, ArithmeticType SourceTy>
4188
- requires traits::is_unit_v<unit<TargetCf, SourceTy>>
4206
+ requires traits::is_unit_v<unit<TargetCf, SourceTy>>
4189
4207
unit (const unit<TargetCf, SourceTy>&) -> unit<TargetCf, SourceTy>;
4190
4208
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>>>
4195
4211
unit (T) -> unit<Cf, T>;
4196
- } // namespace units
4197
4212
4213
+ } // namespace units
4198
4214
4199
4215
4200
4216
// ----------------------------------------------------------------------------------------------------------------------
0 commit comments