4 ms·
I have a project for which I wrote a simple units library. I don't think I'd be able to write any physics-related project now without using it (or a similar lib
by majorexception 3y ago
I have a project for which I wrote a simple units library. I don't think I'd be able to write any physics-related project now without using it (or a similar library). My Quantity class has a set of 8 parameters (7 SI base units and a hack that allows conversion between Hz and radians) + additional Scale and Offset parameters. Scale allows representing units other than SI (like Nautical Miles), Offset is for units like Celsius, for which 0°C == 273.15 K.
I can do things like:
si::Length length = 15_m + 12_nm; // _nm for Nautical Miles
si::Area area = 1_m * 1_km; // Equals to 1000_m2
si::Power power = 1_m / 1_sec / 1_sec; // Compilation error, 1_m/s² is not a si::Power
I don't have every possible User-Defined Literal, of course, so I end up doing this for less common units:
using SomeLocalTypeName = decltype(1_rpm / 1_V);
Something to thing about, when designing such library:
* What is 0_degC + 1_degC? 1_degC or… 273.15_K + 274.15_K = 547.3_K = 274.15_degC? I forbid operations between units if any of them has Offset parameter different than 0. I'm not sure if this is the good solution, though.
* Nm (Newton-meters) is the same unit as Joules. ;-)
- pests 3y agoFor your first point about temp, the proper way would be to convert to Kelvin, do the addition, and back to Celsius.
- majorexception 3y agoYup. So I explicitly deleted operators for °C, so things like 5_degC + 10_degC won't compile.
- pests 3y agoBut cant you just implement operator+(celcius, celcius) that will do the conversion to kelvin and back, since you know for certain the conversion math?
- majorexception 3y agoI did that, but then adding 0_degC + 0_degC gave 273.15_degC. I think that would be surprising to many people. In reality I don't remember ever having to deal with physics formulas that used °C instead of Kelvins, so the only time I need to use °C is when presenting the temperature in the UI: temperature.in<si::Celsius>()
- pests 3y agoDuh. I was thinking too much on the syntax side and not thinking about the physical world; which is ironic considering the discussion topic.
- phanimahesh 3y agoAdding temperatures is not done usually. Mixing substances adds thermal energy. There's no reason I can hink of why allowing plus operator on temperatures is a good idea. You can add temperature differentials, but it is plain addition so long as units are in agreement. And 0C differential is 0F differential, no offsets in conversions.
- Negitivefrags 3y agoI’m not really a fan of the syntax in the article where you multiply the unit with the value. I much prefer your user defined literal approach. But is there any way to make it so you can introduce a new user defined literal for a new composed unit with reasonable syntax?
- majorexception 3y agoSomething like this: auto operator"" _rpmPerVolt (long double x) { return decltype (1_rpm / 1_V)(x); } I have a macro for that: #define SI_DEFINE_LITERAL(xUnit, xliteral) \ [[nodiscard]] \ constexpr Quantity<units::xUnit> \ operator"" xliteral (long double value) \ { \ return Quantity<units::xUnit> (value); \ } \ \ [[nodiscard]] \ constexpr Quantity<units::xUnit> \ operator"" xliteral (unsigned long long value) \ { \ return Quantity<units::xUnit> (value); \ } // Base SI units: SI_DEFINE_LITERAL (Meter, _m) SI_DEFINE_LITERAL (Kilogram, _kg) SI_DEFINE_LITERAL (Second, _s) SI_DEFINE_LITERAL (Ampere, _A) SI_DEFINE_LITERAL (Kelvin, _K) SI_DEFINE_LITERAL (Mole, _mol) SI_DEFINE_LITERAL (Candela, _cd) SI_DEFINE_LITERAL (Radian, _rad) ...and a loong list of other common units here. The additional types are defined like this, in another file: using Foot = ScaledUnit<Meter, std::ratio<1'200, 3'937>>; using Mile = ScaledUnit<Meter, std::ratio<1'609'344, 1'000>>; using NauticalMile = ScaledUnit<Meter, std::ratio<1'852, 1>>; using Inch = ScaledUnit<Meter, std::ratio<254, 10'000>>; And then I use SI_DEFINE_LITERAL (NauticalMile, _nm); etc.
- thfuran 3y agoYeah, Celsius is awkward because it's basically used as both an actual temperature and as an interval depending on context, and mixing them is bad news. A similar sort of distinction often shows up in datetime libraries between an instant and a duration/timespan, but I'm not sure it's worth doing in a unit library. Just forcing kelvin for intervals probably isn't too onerous for most uses, and I can't think of any unit it would really apply to other than °C/F, whosoever dares mix units of measure with time zones notwithstanding.