Skip to content

Commit

Permalink
fix: CTAD that works on clang as well
Browse files Browse the repository at this point in the history
  • Loading branch information
Nic Holthaus committed Dec 17, 2024
1 parent d97cb13 commit 2d12992
Showing 1 changed file with 43 additions and 23 deletions.
66 changes: 43 additions & 23 deletions include/units/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -4152,31 +4152,51 @@ namespace std

namespace units
{
// chrono deduction guide
template<ArithmeticType Rep, RatioType Period>
unit(std::chrono::duration<Rep, Period>) -> unit<conversion_factor<Period, dimension::time>, Rep>;

// Conversion factor from Target, type from Source
template<ConversionFactorType TargetCf = dimensionless<>, ConversionFactorType SourceCf = dimensionless<>, ArithmeticType SourceTy = double>
requires traits::is_unit_v<unit<SourceCf, SourceTy>> && traits::is_conversion_factor_v<TargetCf>
unit(const unit<SourceCf, SourceTy>&) -> unit<TargetCf, SourceTy>;

// Matching Target and Source factors
template<ConversionFactorType TargetCf, ArithmeticType SourceTy>
requires traits::is_unit_v<unit<TargetCf, SourceTy>>
unit(const unit<TargetCf, SourceTy>&) -> unit<TargetCf, SourceTy>;

// Deduce from the same unit type
template<ConversionFactorType Cf, ArithmeticType Ty>
unit(const unit<Cf, Ty>&) -> unit<Cf, Ty>;

// Deduce type from arithmetic type
template<typename T,
typename Cf = dimension::dimensionless, // Default conversion factor to dimensionless
typename = std::enable_if_t<std::is_arithmetic_v<T>>>
unit(T) -> unit<Cf, T>;
// 1) chrono deduction guide
template<ArithmeticType Rep, RatioType Period>
unit(std::chrono::duration<Rep, Period>)
-> unit<conversion_factor<Period, dimension::time>, Rep>;

// 2) Dimensionless fallback:
// Now restricted to apply only if the source is exactly the base dimensionless unit,
// i.e. conversion_factor<std::ratio<1>, dimension::dimensionless> with no pi exponent or translation.
template<ArithmeticType SourceTy, ConversionFactorType SourceCf>
requires (
traits::is_unit_v<unit<SourceCf, SourceTy>> &&
std::is_same_v<typename SourceCf::dimension_type, dimension::dimensionless> &&
// Ensuring it's the pure base dimensionless factor:
std::ratio_equal<typename SourceCf::conversion_ratio, std::ratio<1>>::value &&
std::ratio_equal<typename SourceCf::pi_exponent_ratio, std::ratio<0>>::value &&
std::ratio_equal<typename SourceCf::translation_ratio, std::ratio<0>>::value
)
unit(const unit<SourceCf, SourceTy>&)
-> unit<conversion_factor<std::ratio<1>, dimension::dimensionless>, SourceTy>;

// 3) General conversion factor from Target, type from Source:
// Applies only if TargetCf differs from SourceCf and they share the same dimension.
template<ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
requires (
traits::is_unit_v<unit<SourceCf, SourceTy>> &&
traits::is_conversion_factor_v<TargetCf> &&
traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
!std::is_same_v<SourceCf, TargetCf>
)
unit(const unit<SourceCf, SourceTy>&) -> unit<TargetCf, SourceTy>;

// 4) Matching Target and Source factors exactly
template<ConversionFactorType TargetCf, ArithmeticType SourceTy>
requires traits::is_unit_v<unit<TargetCf, SourceTy>>
unit(const unit<TargetCf, SourceTy>&) -> unit<TargetCf, SourceTy>;

// 5) Deduce type from arithmetic type (dimensionless by default)
template<typename T,
typename Cf = dimension::dimensionless,
typename = std::enable_if_t<std::is_arithmetic_v<T>>>
unit(T) -> unit<Cf, T>;
} // namespace units



//----------------------------------------------------------------------------------------------------------------------
// JSON SUPPORT
//----------------------------------------------------------------------------------------------------------------------
Expand Down

0 comments on commit 2d12992

Please sign in to comment.