mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 19:04:27 +02:00
Dimension template parameter removed from quantity
This commit is contained in:
249
doc/DESIGN.md
249
doc/DESIGN.md
@@ -50,21 +50,11 @@ point of view the most important is a quantity.
|
||||
Quantity is a concrete amount of a unit for a specified dimension with a specific representation:
|
||||
|
||||
```cpp
|
||||
units::quantity<units::dimension_length, units::kilometer, double> d1(123);
|
||||
auto d2 = 123_km; // units::quantity<units::dimension_length, units::kilometer, std::int64_t>
|
||||
units::quantity<units::kilometer, double> d1(123);
|
||||
auto d2 = 123_km; // units::quantity<units::kilometer, std::int64_t>
|
||||
```
|
||||
|
||||
There are helper aliases provided to improve the work with quantities:
|
||||
|
||||
```
|
||||
template<Unit U = struct meter, Number Rep = double>
|
||||
using length = quantity<dimension_length, U, Rep>;
|
||||
|
||||
units::length d1(123); // units::length<units::meter, int>
|
||||
units::length<units::mile> d2(3.14); // units::length<units::mile, double>
|
||||
```
|
||||
|
||||
Also there are C++ concepts provided for each such quantity type:
|
||||
There are C++ concepts provided for each such quantity type:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
@@ -241,8 +231,7 @@ concept Unit =
|
||||
expressed in a specific unit of that dimension:
|
||||
|
||||
```cpp
|
||||
template<Dimension D, Unit U, Number Rep>
|
||||
requires std::Same<D, typename U::dimension>
|
||||
template<Unit U, Scalar Rep>
|
||||
class quantity;
|
||||
```
|
||||
|
||||
@@ -259,29 +248,36 @@ concept Quantity =
|
||||
member types and functions as below:
|
||||
|
||||
```cpp
|
||||
template<Dimension D, Unit U, Number Rep>
|
||||
requires std::Same<D, typename U::dimension>
|
||||
template<Unit U, Scalar Rep>
|
||||
class quantity {
|
||||
public:
|
||||
using dimension = D;
|
||||
using unit = U;
|
||||
using rep = Rep;
|
||||
using dimension = U::dimension;
|
||||
|
||||
template<Dimension D1, Unit U1, Number Rep1, Dimension D2, Unit U2, Number Rep2>
|
||||
requires treat_as_floating_point<std::common_type_t<Rep1, Rep2>> || std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1
|
||||
quantity<dimension_multiply_t<D1, D2>, downcasting_traits_t<unit<dimension_multiply_t<D1, D2>, std::ratio_multiply<typename U1::ratio, typename U2::ratio>>>, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator*(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs);
|
||||
[[nodiscard]] static constexpr quantity one() noexcept { return quantity(quantity_values<Rep>::one()); }
|
||||
|
||||
template<Number Rep1, Dimension D, Unit U, Number Rep2>
|
||||
quantity<dim_invert_t<D>, downcasting_traits_t<unit<dim_invert_t<D>, std::ratio<U::ratio::den, U::ratio::num>>>, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator/(const Rep1& v,
|
||||
const quantity<D, U, Rep2>& q) [[expects: q != quantity<D, U, Rep2>(0)]];
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
requires treat_as_floating_point<decltype(lhs.count() * rhs.count())> ||
|
||||
(std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1)
|
||||
[[nodiscard]] constexpr Quantity operator*(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs);
|
||||
|
||||
template<Dimension D1, Unit U1, Number Rep1, Dimension D2, Unit U2, Number Rep2>
|
||||
requires treat_as_floating_point<std::common_type_t<Rep1, Rep2>> || std::ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1
|
||||
quantity<dimension_divide_t<D1, D2>, downcasting_traits_t<unit<dimension_divide_t<D1, D2>, std::ratio_divide<typename U1::ratio, typename U2::ratio>>>, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator/(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs) [[expects: rhs != quantity<D, U2, Rep2>(0)]];
|
||||
template<Scalar Rep1, typename U, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator/(const Rep1& v,
|
||||
const quantity<U, Rep2>& q)
|
||||
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
[[nodiscard]] constexpr Scalar operator/(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs);
|
||||
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
requires (!std::Same<typename U1::dimension, typename U2::dimension>) &&
|
||||
(treat_as_floating_point<decltype(lhs.count() / rhs.count())> ||
|
||||
(ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1))
|
||||
[[nodiscard]] constexpr Quantity operator/(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs);
|
||||
};
|
||||
```
|
||||
|
||||
@@ -308,35 +304,35 @@ the best user experience as possible.
|
||||
For example with template aliases usage the following code:
|
||||
|
||||
```cpp
|
||||
const Velocity t = 20_s;
|
||||
const Velocity auto t = 20_s;
|
||||
```
|
||||
|
||||
could generate a following compile time error:
|
||||
|
||||
```text
|
||||
C:\repos\units\example\example.cpp:39:22: error: deduced initializer does not satisfy placeholder constraints
|
||||
const Velocity t = 20_s;
|
||||
^~~~
|
||||
In file included from C:\repos\units\example\example.cpp:23:
|
||||
C:/repos/units/src/include/units/si/velocity.h:41:16: note: within 'template<class T> concept const bool units::Velocity<T> [with T = units::quantity<units::dimension<units::exp<units::base_dim_time, 1> >, units::unit<units::dimension<units::exp<units::base_dim_time, 1> >, std::ratio<1> >, long long int>]'
|
||||
<path>\example\example.cpp:39:22: error: deduced initializer does not satisfy placeholder constraints
|
||||
const Velocity auto t = 20_s;
|
||||
^~~~
|
||||
In file included from <path>\example\example.cpp:23:
|
||||
<path>/src/include/units/si/velocity.h:41:16: note: within 'template<class T> concept const bool units::Velocity<T> [with T = units::quantity<units::unit<units::dimension<units::exp<units::base_dim_time, 1> >, std::ratio<1> >, long long int>]'
|
||||
concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>;
|
||||
^~~~~~~~
|
||||
In file included from C:/repos/units/src/include/units/bits/tools.h:25,
|
||||
from C:/repos/units/src/include/units/dimension.h:25,
|
||||
from C:/repos/units/src/include/units/si/base_dimensions.h:25,
|
||||
from C:/repos/units/src/include/units/si/velocity.h:25,
|
||||
from C:\repos\units\example\example.cpp:23:
|
||||
C:/repos/units/src/include/units/bits/stdconcepts.h:33:18: note: within 'template<class T, class U> concept const bool std::Same<T, U> [with T = units::dimension<units::exp<units::base_dim_time, 1> >; U = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >]'
|
||||
In file included from <path>/src/include/units/bits/tools.h:25,
|
||||
from <path>/src/include/units/dimension.h:25,
|
||||
from <path>/src/include/units/si/base_dimensions.h:25,
|
||||
from <path>/src/include/units/si/velocity.h:25,
|
||||
from <path>\example\example.cpp:23:
|
||||
<path>/src/include/units/bits/stdconcepts.h:33:18: note: within 'template<class T, class U> concept const bool std::Same<T, U> [with T = units::dimension<units::exp<units::base_dim_time, 1> >; U = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >]'
|
||||
concept Same = std::is_same_v<T, U>;
|
||||
^~~~
|
||||
C:/repos/units/src/include/units/bits/stdconcepts.h:33:18: note: 'std::is_same_v' evaluated to false
|
||||
<path>/src/include/units/bits/stdconcepts.h:33:18: note: 'std::is_same_v' evaluated to false
|
||||
```
|
||||
|
||||
Time and velocity are not that complicated dimensions and there are much more complicated dimensions
|
||||
out there, but even for those dimensions
|
||||
|
||||
```text
|
||||
[with T = units::quantity<units::dimension<units::exp<units::base_dim_time, 1> >, units::unit<units::dimension<units::exp<units::base_dim_time, 1> >, std::ratio<1> >, long long int>]
|
||||
[with T = units::quantity<units::unit<units::dimension<units::exp<units::base_dim_time, 1> >, std::ratio<1> >, long long int>]
|
||||
```
|
||||
|
||||
and
|
||||
@@ -351,28 +347,28 @@ That is why it was decided to provide automated downcasting capability when poss
|
||||
same code will result with such an error:
|
||||
|
||||
```text
|
||||
C:\repos\units\example\example.cpp:40:22: error: deduced initializer does not satisfy placeholder constraints
|
||||
<path>\example\example.cpp:40:22: error: deduced initializer does not satisfy placeholder constraints
|
||||
const Velocity t = 20_s;
|
||||
^~~~
|
||||
In file included from C:\repos\units\example\example.cpp:23:
|
||||
C:/repos/units/src/include/units/si/velocity.h:48:16: note: within 'template<class T> concept const bool units::Velocity<T> [with T = units::quantity<units::dimension_time, units::second, long long int>]'
|
||||
In file included from <path>\example\example.cpp:23:
|
||||
<path>/src/include/units/si/velocity.h:48:16: note: within 'template<class T> concept const bool units::Velocity<T> [with T = units::quantity<units::second, long long int>]'
|
||||
concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>;
|
||||
^~~~~~~~
|
||||
In file included from C:/repos/units/src/include/units/bits/tools.h:25,
|
||||
from C:/repos/units/src/include/units/dimension.h:25,
|
||||
from C:/repos/units/src/include/units/si/base_dimensions.h:25,
|
||||
from C:/repos/units/src/include/units/si/velocity.h:25,
|
||||
from C:\repos\units\example\example.cpp:23:
|
||||
C:/repos/units/src/include/units/bits/stdconcepts.h:33:18: note: within 'template<class T, class U> concept const bool std::Same<T, U> [with T = units::dimension_time; U = units::dimension_velocity]'
|
||||
In file included from <path>/src/include/units/bits/tools.h:25,
|
||||
from <path>/src/include/units/dimension.h:25,
|
||||
from <path>/src/include/units/si/base_dimensions.h:25,
|
||||
from <path>/src/include/units/si/velocity.h:25,
|
||||
from <path>\example\example.cpp:23:
|
||||
<path>/src/include/units/bits/stdconcepts.h:33:18: note: within 'template<class T, class U> concept const bool std::Same<T, U> [with T = units::dimension_time; U = units::dimension_velocity]'
|
||||
concept Same = std::is_same_v<T, U>;
|
||||
^~~~
|
||||
C:/repos/units/src/include/units/bits/stdconcepts.h:33:18: note: 'std::is_same_v' evaluated to false
|
||||
<path>/src/include/units/bits/stdconcepts.h:33:18: note: 'std::is_same_v' evaluated to false
|
||||
```
|
||||
|
||||
Now
|
||||
|
||||
```text
|
||||
[with T = units::quantity<units::dimension_time, units::second, long long int>]
|
||||
[with T = units::quantity<units::second, long long int>]
|
||||
```
|
||||
|
||||
and
|
||||
@@ -383,20 +379,32 @@ and
|
||||
|
||||
are not arguably much easier to understand thus provide better user experience.
|
||||
|
||||
downcasting capability is provided through dedicated `downcasting_traits`, a few helper aliases and by
|
||||
Downcasting capability is provided through dedicated `downcasting_traits`, concept, a few helper aliases and by
|
||||
`base_type` member type in `downcast_base` class template.
|
||||
|
||||
```cpp
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using base_type = BaseType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept bool Downcastable =
|
||||
requires {
|
||||
typename T::base_type;
|
||||
} &&
|
||||
std::DerivedFrom<T, downcast_base<typename T::base_type>>;
|
||||
|
||||
template<Downcastable T>
|
||||
using downcast_from = T::base_type;
|
||||
|
||||
template<typename T>
|
||||
template<Downcastable T>
|
||||
using downcast_to = std::type_identity<T>;
|
||||
|
||||
template<typename T>
|
||||
template<Downcastable T>
|
||||
struct downcasting_traits : downcast_to<T> {};
|
||||
|
||||
template<typename T>
|
||||
template<Downcastable T>
|
||||
using downcasting_traits_t = downcasting_traits<T>::type;
|
||||
```
|
||||
|
||||
@@ -424,21 +432,14 @@ struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_d
|
||||
template<> struct downcasting_traits<downcast_from<dimension_velocity>> : downcast_to<dimension_velocity> {};
|
||||
```
|
||||
|
||||
2. Provide `quantity` class template partial specialization for new dimension and provide its base type:
|
||||
|
||||
```cpp
|
||||
template<Unit U = struct meter_per_second, Number Rep = double>
|
||||
using velocity = quantity<dimension_velocity, U, Rep>;
|
||||
```
|
||||
|
||||
3. Define a concept that will match a new dimension:
|
||||
2. Define a concept that will match a new dimension:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>;
|
||||
```
|
||||
|
||||
4. Define units and provide downcasting traits for them:
|
||||
3. Define units and provide downcasting traits for them:
|
||||
|
||||
- base unit
|
||||
|
||||
@@ -465,11 +466,11 @@ template<> struct downcasting_traits<downcast_from<kilometer_per_hour>> : downca
|
||||
|
||||
```cpp
|
||||
inline namespace literals {
|
||||
constexpr auto operator""_mps(unsigned long long l) { return velocity<meter_per_second, std::int64_t>(l); }
|
||||
constexpr auto operator""_mps(long double l) { return velocity<meter_per_second, long double>(l); }
|
||||
constexpr auto operator""_mps(unsigned long long l) { return quantity<meter_per_second, std::int64_t>(l); }
|
||||
constexpr auto operator""_mps(long double l) { return quantity<meter_per_second, long double>(l); }
|
||||
|
||||
constexpr auto operator""_kmph(unsigned long long l) { return velocity<kilometer_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_kmph(long double l) { return velocity<kilometer_per_hour, long double>(l); }
|
||||
constexpr auto operator""_kmph(unsigned long long l) { return quantity<kilometer_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_kmph(long double l) { return quantity<kilometer_per_hour, long double>(l); }
|
||||
}
|
||||
```
|
||||
|
||||
@@ -507,101 +508,39 @@ Additionally, it should make the error logs even shorter thus easier to understa
|
||||
|
||||
1. Should we ensure that dimension is always a result of `make_dimension`? How to do it?
|
||||
|
||||
2. Should we provide strong types and downcasting_traits for `quantity` type?
|
||||
2. What to do with `time` which is ambiguous (conflict wit ANSI C)?
|
||||
|
||||
In such a case all the operators have to be provided to a child class. Or maybe use CRTP?
|
||||
3. What to do with `std::chrono::duration`?
|
||||
|
||||
3. What to do with `time` which is ambiguous (conflict wit ANSI C)?
|
||||
4. Should we provide `seconds<int>` or stay with `quantity<second, int>`?
|
||||
|
||||
4. What to do with `std::chrono::duration`? Is it possible to make it derive from
|
||||
`quantity<dimension_time, U, Rep>` which will most probably an ABI break? Alternatively,
|
||||
should we provide specialization of `quantity<dimension_time, U, Rep>` to work with/covnert
|
||||
from/to `std::duration`?
|
||||
5. What is the best way to add support for temperatures?
|
||||
|
||||
5. Should we provide `seconds<int>` or stay with `time<second, int>`? What about CTAD problem
|
||||
for `units::length<units::mile> d3(3);`?
|
||||
Temperature absolute values not only require `std::ratio` but also should be adjusted/shifted
|
||||
by some constant values (i.e. [°C] = [K] − 273.15). Relative temperatures does need an offset.
|
||||
Users will most probably have problems with differentiating those two. Maybe the best solution
|
||||
is to provide only `K` support in quantity and provide non-member helper conversion functions
|
||||
with verbose names to convert to `°C` and `°C`?
|
||||
|
||||
6. What is the best way to add support for temperatures?
|
||||
6. Do we need non-linear scale?
|
||||
|
||||
Temperatures not only require `std::ratio` but also should be adjusted/shifted by some
|
||||
constant values (i.e. [°C] = [K] − 273.15).
|
||||
7. Should we provide cmath-like functions for quantities?
|
||||
|
||||
7. Should we use `units::multiply` or stay with `std::ratio` for multiplication?
|
||||
8. What should be the resulting type of `auto d = 1_km + 1_ft;`?
|
||||
|
||||
8. Should we consider making `units::multiply` and `units::offset` a non-class template parameters
|
||||
as they provide different ratio values rather than types?
|
||||
9. Should we require explicit casts (i.e. quantity_cast) between different systems of
|
||||
measurement?
|
||||
|
||||
In example instead:
|
||||
10. Should we support integral representations?
|
||||
|
||||
```cpp
|
||||
struct celsius : unit<dimension_temperature, convert<offset<-27315, 100>>> {};
|
||||
```
|
||||
11. Provide ostream overloads to print quantity units (use `std::format`)?
|
||||
|
||||
we could think about something like:
|
||||
|
||||
```cpp
|
||||
struct celsius : unit<dimension_temperature, kelvin() - 27315/100>>> {};
|
||||
```
|
||||
|
||||
9. Do we need non-linear scale?
|
||||
|
||||
10. Should we provide cmath-like functions for quantities?
|
||||
|
||||
11. What should be the resulting type of `auto d = 1_km + 1_ft;`?
|
||||
|
||||
12. Should we require explicit casts (i.e. quantity_cast) between different systems of
|
||||
measurement?
|
||||
|
||||
13. Should we provide Boost-like support for a `quantity_cast` to a reference that allows
|
||||
direct access to the underlying value of a quantity variable?
|
||||
|
||||
14. What should be the default representation (integral or `double`)?
|
||||
|
||||
15. Provide ostream overloads to print quantity units (use `std::format`)?
|
||||
|
||||
16. Should we provide support for dimensionless quantities?
|
||||
12. Should we provide support for dimensionless quantities?
|
||||
|
||||
Because dimensionless quantities have no associated units, they behave as normal scalars,
|
||||
and allow implicit conversion to and from the underlying value type or types that are
|
||||
convertible to/from that value type.
|
||||
|
||||
17. Should we leave `quantity` and specific dimensions as
|
||||
```cpp
|
||||
template<Dimension D, Unit U, Number Rep>
|
||||
requires std::Same<D, typename U::dimension>
|
||||
class quantity;
|
||||
|
||||
template<Unit U = meter_per_second, Number Rep = double>
|
||||
using velocity = quantity<dimension_velocity, U, Rep>;
|
||||
|
||||
units::velocity<units::kilometer_per_hour> kmph = avg_speed(d, t);
|
||||
```
|
||||
or maybe we should leave the dimension only in unit
|
||||
```cpp
|
||||
template<Unit U, Number Rep>
|
||||
class quantity;
|
||||
|
||||
units::quantity<units::kilometer_per_hour> kmph = avg_speed(d, t);
|
||||
```
|
||||
which will simplify the design and shorten compile time errors but possibly will add
|
||||
more ambiguity to some cases. For example when using CTAD:
|
||||
```cpp
|
||||
units::velocity kmph = avg_speed(d, t);
|
||||
```
|
||||
vs
|
||||
```cpp
|
||||
units::quantity kmph = avg_speed(d, t);
|
||||
```
|
||||
It would be also incopatible with concepts named i.e. `Velocity`.
|
||||
|
||||
18. Should we standardize accompany tools (`type_list` operations, `static_sign`, `static_abs`,
|
||||
`static_gcd`, `common_ratio`)?
|
||||
|
||||
19. Do we need to support fractional exponents (i.e. `dimension<exp<"length", 2, 3>>` as 2/3)?
|
||||
|
||||
20. implicit conversion of quantity<Unit,Y> to quantity<Unit,Z> is allowed if Y and Z are implicitly convertible.
|
||||
assignment between quantity<Unit,Y> and quantity<Unit,Z> is allowed if Y and Z are implicitly convertible.
|
||||
|
||||
21. explicit conversion between quantity<Unit1,Y> and quantity<Unit2,Z> is allowed if Unit1 and Unit2 have the same dimensions and if Y and Z are implicitly convertible.
|
||||
implicit conversion between quantity<Unit1,Y> and quantity<Unit2,Z> is allowed if Unit1 reduces to exactly the same combination of base units as Unit2 and if Y and Z are convertible.
|
||||
13. Should we standardize accompany tools (`downcasting_traits`, `type_list` operations, `common_ratio`, etc)?
|
||||
|
||||
14. Do we need to support fractional exponents (i.e. `dimension<exp<"length", 2, 3>>` as 2/3)?
|
@@ -38,13 +38,13 @@ void example_1(V v, T t)
|
||||
{
|
||||
const units::Length distance = v * t;
|
||||
std::cout << "A car driving " << v.count() << " km/h in a time of " << t.count() << " minutes will pass "
|
||||
<< units::quantity_cast<units::length<units::meter, double>>(distance).count() << " meters.\n";
|
||||
<< units::quantity_cast<units::quantity<units::meter, double>>(distance).count() << " meters.\n";
|
||||
}
|
||||
|
||||
void example_2(double distance_v, double duration_v)
|
||||
{
|
||||
units::length<units::kilometer> distance(distance_v);
|
||||
units::time<units::hour> duration(duration_v);
|
||||
units::quantity<units::kilometer> distance(distance_v);
|
||||
units::quantity<units::hour> duration(duration_v);
|
||||
const auto kmph = avg_speed(distance, duration);
|
||||
std::cout << "Average speed of a car that makes " << distance.count() << " km in "
|
||||
<< duration.count() << " hours is " << kmph.count() << " km/h.\n";
|
||||
|
@@ -32,9 +32,6 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Area = Quantity<T> && std::Same<typename T::dimension, dimension_area>;
|
||||
|
||||
template<Unit U = struct square_meter, Number Rep = double>
|
||||
using area = quantity<dimension_area, U, Rep>;
|
||||
|
||||
struct square_millimeter : derived_unit<dimension_area, millimeter> {};
|
||||
template<> struct downcasting_traits<downcast_from<square_millimeter>> : downcast_to<square_millimeter> {};
|
||||
|
||||
@@ -53,20 +50,20 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// sq_mm
|
||||
constexpr auto operator""_sq_mm(unsigned long long l) { return area<square_millimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_mm(long double l) { return area<square_millimeter, long double>(l); }
|
||||
constexpr auto operator""_sq_mm(unsigned long long l) { return quantity<square_millimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_mm(long double l) { return quantity<square_millimeter, long double>(l); }
|
||||
|
||||
// sq_cm
|
||||
constexpr auto operator""_sq_cm(unsigned long long l) { return area<square_centimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_cm(long double l) { return area<square_centimeter, long double>(l); }
|
||||
constexpr auto operator""_sq_cm(unsigned long long l) { return quantity<square_centimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_cm(long double l) { return quantity<square_centimeter, long double>(l); }
|
||||
|
||||
// sq_m
|
||||
constexpr auto operator""_sq_m(unsigned long long l) { return area<square_meter, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_m(long double l) { return area<square_meter, long double>(l); }
|
||||
constexpr auto operator""_sq_m(unsigned long long l) { return quantity<square_meter, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_m(long double l) { return quantity<square_meter, long double>(l); }
|
||||
|
||||
// sq_km
|
||||
constexpr auto operator""_sq_km(unsigned long long l) { return area<square_kilometer, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_km(long double l) { return area<square_kilometer, long double>(l); }
|
||||
constexpr auto operator""_sq_km(unsigned long long l) { return quantity<square_kilometer, std::int64_t>(l); }
|
||||
constexpr auto operator""_sq_km(long double l) { return quantity<square_kilometer, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -37,6 +37,7 @@ namespace std {
|
||||
using type_identity_t = typename type_identity<T>::type;
|
||||
|
||||
#endif // UNITS_HAS_STD_TYPE_IDENTITY
|
||||
|
||||
// concepts
|
||||
using experimental::ranges::Same;
|
||||
using experimental::ranges::Integral;
|
||||
|
@@ -33,17 +33,14 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Current = Quantity<T> && std::Same<typename T::dimension, dimension_current>;
|
||||
|
||||
template<Unit U = struct ampere, Number Rep = double>
|
||||
using current = quantity<dimension_current, U, Rep>;
|
||||
|
||||
struct ampere : unit<dimension_current> {};
|
||||
template<> struct downcasting_traits<downcast_from<ampere>> : downcast_to<ampere> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
// A
|
||||
constexpr auto operator""_A(unsigned long long l) { return current<ampere, std::int64_t>(l); }
|
||||
constexpr auto operator""_A(long double l) { return current<ampere, long double>(l); }
|
||||
constexpr auto operator""_A(unsigned long long l) { return quantity<ampere, std::int64_t>(l); }
|
||||
constexpr auto operator""_A(long double l) { return quantity<ampere, long double>(l); }
|
||||
|
||||
}
|
||||
|
||||
|
@@ -33,9 +33,6 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Frequency = Quantity<T> && std::Same<typename T::dimension, dimension_frequency>;
|
||||
|
||||
template<Unit U = struct hertz, Number Rep = double>
|
||||
using frequency = quantity<dimension_frequency, U, Rep>;
|
||||
|
||||
struct hertz : derived_unit<dimension_frequency, second> {};
|
||||
template<> struct downcasting_traits<downcast_from<hertz>> : downcast_to<hertz> {};
|
||||
|
||||
@@ -57,28 +54,28 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// mHz
|
||||
constexpr auto operator""_mHz(unsigned long long l) { return frequency<millihertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_mHz(long double l) { return frequency<millihertz, long double>(l); }
|
||||
constexpr auto operator""_mHz(unsigned long long l) { return quantity<millihertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_mHz(long double l) { return quantity<millihertz, long double>(l); }
|
||||
|
||||
// Hz
|
||||
constexpr auto operator""_Hz(unsigned long long l) { return frequency<hertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_Hz(long double l) { return frequency<hertz, long double>(l); }
|
||||
constexpr auto operator""_Hz(unsigned long long l) { return quantity<hertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_Hz(long double l) { return quantity<hertz, long double>(l); }
|
||||
|
||||
// kHz
|
||||
constexpr auto operator""_kHz(unsigned long long l) { return frequency<kilohertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_kHz(long double l) { return frequency<kilohertz, long double>(l); }
|
||||
constexpr auto operator""_kHz(unsigned long long l) { return quantity<kilohertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_kHz(long double l) { return quantity<kilohertz, long double>(l); }
|
||||
|
||||
// MHz
|
||||
constexpr auto operator""_MHz(unsigned long long l) { return frequency<megahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_MHz(long double l) { return frequency<megahertz, long double>(l); }
|
||||
constexpr auto operator""_MHz(unsigned long long l) { return quantity<megahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_MHz(long double l) { return quantity<megahertz, long double>(l); }
|
||||
|
||||
// GHz
|
||||
constexpr auto operator""_GHz(unsigned long long l) { return frequency<gigahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_GHz(long double l) { return frequency<gigahertz, long double>(l); }
|
||||
constexpr auto operator""_GHz(unsigned long long l) { return quantity<gigahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_GHz(long double l) { return quantity<gigahertz, long double>(l); }
|
||||
|
||||
// THz
|
||||
constexpr auto operator""_THz(unsigned long long l) { return frequency<terahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_THz(long double l) { return frequency<terahertz, long double>(l); }
|
||||
constexpr auto operator""_THz(unsigned long long l) { return quantity<terahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_THz(long double l) { return quantity<terahertz, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -33,9 +33,6 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Length = Quantity<T> && std::Same<typename T::dimension, dimension_length>;
|
||||
|
||||
template<Unit U = struct meter, Number Rep = double>
|
||||
using length = quantity<dimension_length, U, Rep>;
|
||||
|
||||
// SI units
|
||||
struct meter : unit<dimension_length> {};
|
||||
template<> struct downcasting_traits<downcast_from<meter>> : downcast_to<meter> {};
|
||||
@@ -52,20 +49,20 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// mm
|
||||
constexpr auto operator""_mm(unsigned long long l) { return length<millimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_mm(long double l) { return length<millimeter, long double>(l); }
|
||||
constexpr auto operator""_mm(unsigned long long l) { return quantity<millimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_mm(long double l) { return quantity<millimeter, long double>(l); }
|
||||
|
||||
// cm
|
||||
constexpr auto operator""_cm(unsigned long long l) { return length<centimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_cm(long double l) { return length<centimeter, long double>(l); }
|
||||
constexpr auto operator""_cm(unsigned long long l) { return quantity<centimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_cm(long double l) { return quantity<centimeter, long double>(l); }
|
||||
|
||||
// m
|
||||
constexpr auto operator""_m(unsigned long long l) { return length<meter, std::int64_t>(l); }
|
||||
constexpr auto operator""_m(long double l) { return length<meter, long double>(l); }
|
||||
constexpr auto operator""_m(unsigned long long l) { return quantity<meter, std::int64_t>(l); }
|
||||
constexpr auto operator""_m(long double l) { return quantity<meter, long double>(l); }
|
||||
|
||||
// km
|
||||
constexpr auto operator""_km(unsigned long long l) { return length<kilometer, std::int64_t>(l); }
|
||||
constexpr auto operator""_km(long double l) { return length<kilometer, long double>(l); }
|
||||
constexpr auto operator""_km(unsigned long long l) { return quantity<kilometer, std::int64_t>(l); }
|
||||
constexpr auto operator""_km(long double l) { return quantity<kilometer, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
@@ -85,20 +82,20 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// yd
|
||||
constexpr auto operator""_yd(unsigned long long l) { return length<yard, std::int64_t>(l); }
|
||||
constexpr auto operator""_yd(long double l) { return length<yard, long double>(l); }
|
||||
constexpr auto operator""_yd(unsigned long long l) { return quantity<yard, std::int64_t>(l); }
|
||||
constexpr auto operator""_yd(long double l) { return quantity<yard, long double>(l); }
|
||||
|
||||
// ft
|
||||
constexpr auto operator""_ft(unsigned long long l) { return length<foot, std::int64_t>(l); }
|
||||
constexpr auto operator""_ft(long double l) { return length<foot, long double>(l); }
|
||||
constexpr auto operator""_ft(unsigned long long l) { return quantity<foot, std::int64_t>(l); }
|
||||
constexpr auto operator""_ft(long double l) { return quantity<foot, long double>(l); }
|
||||
|
||||
// in
|
||||
constexpr auto operator""_in(unsigned long long l) { return length<inch, std::int64_t>(l); }
|
||||
constexpr auto operator""_in(long double l) { return length<inch, long double>(l); }
|
||||
constexpr auto operator""_in(unsigned long long l) { return quantity<inch, std::int64_t>(l); }
|
||||
constexpr auto operator""_in(long double l) { return quantity<inch, long double>(l); }
|
||||
|
||||
// mi
|
||||
constexpr auto operator""_mi(unsigned long long l) { return length<mile, std::int64_t>(l); }
|
||||
constexpr auto operator""_mi(long double l) { return length<mile, long double>(l); }
|
||||
constexpr auto operator""_mi(unsigned long long l) { return quantity<mile, std::int64_t>(l); }
|
||||
constexpr auto operator""_mi(long double l) { return quantity<mile, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -33,17 +33,14 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool LuminousIntensity = Quantity<T> && std::Same<typename T::dimension, dimension_luminous_intensity>;
|
||||
|
||||
template<Unit U = struct candela, Number Rep = double>
|
||||
using luminous_intensity = quantity<dimension_luminous_intensity, U, Rep>;
|
||||
|
||||
struct candela : unit<dimension_luminous_intensity> {};
|
||||
template<> struct downcasting_traits<downcast_from<candela>> : downcast_to<candela> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
// cd
|
||||
constexpr auto operator""_cd(unsigned long long l) { return luminous_intensity<candela, std::int64_t>(l); }
|
||||
constexpr auto operator""_cd(long double l) { return luminous_intensity<candela, long double>(l); }
|
||||
constexpr auto operator""_cd(unsigned long long l) { return quantity<candela, std::int64_t>(l); }
|
||||
constexpr auto operator""_cd(long double l) { return quantity<candela, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -33,9 +33,6 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Mass = Quantity<T> && std::Same<typename T::dimension, dimension_mass>;
|
||||
|
||||
template<Unit U = class kilogram, Number Rep = double>
|
||||
using mass = quantity<dimension_mass, U, Rep>;
|
||||
|
||||
struct gram : unit<dimension_mass, ratio<1, 1000>> {};
|
||||
template<> struct downcasting_traits<downcast_from<gram>> : downcast_to<gram> {};
|
||||
|
||||
@@ -45,12 +42,12 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// g
|
||||
constexpr auto operator""_g(unsigned long long l) { return mass<gram, std::int64_t>(l); }
|
||||
constexpr auto operator""_g(long double l) { return mass<gram, long double>(l); }
|
||||
constexpr auto operator""_g(unsigned long long l) { return quantity<gram, std::int64_t>(l); }
|
||||
constexpr auto operator""_g(long double l) { return quantity<gram, long double>(l); }
|
||||
|
||||
// kg
|
||||
constexpr auto operator""_kg(unsigned long long l) { return mass<kilogram, std::int64_t>(l); }
|
||||
constexpr auto operator""_kg(long double l) { return mass<kilogram, long double>(l); }
|
||||
constexpr auto operator""_kg(unsigned long long l) { return quantity<kilogram, std::int64_t>(l); }
|
||||
constexpr auto operator""_kg(long double l) { return quantity<kilogram, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -45,14 +45,13 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Scalar = Number<T> && !Quantity<T>;
|
||||
|
||||
template<Dimension D, Unit U, Scalar Rep>
|
||||
requires std::Same<D, typename U::dimension>
|
||||
template<Unit U, Scalar Rep>
|
||||
class quantity;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<Dimension D, Unit U, Scalar Rep>
|
||||
inline constexpr bool is_quantity<quantity<D, U, Rep>> = true;
|
||||
template<Unit U, Scalar Rep>
|
||||
inline constexpr bool is_quantity<quantity<U, Rep>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -60,14 +59,15 @@ namespace units {
|
||||
template<Quantity Q1, Quantity Q2, Scalar Rep>
|
||||
struct common_quantity;
|
||||
|
||||
template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2, Scalar Rep>
|
||||
struct common_quantity<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
|
||||
using type = quantity<D, U, Rep>;
|
||||
template<Unit U, Scalar Rep1, Scalar Rep2, Scalar Rep>
|
||||
struct common_quantity<quantity<U, Rep1>, quantity<U, Rep2>, Rep> {
|
||||
using type = quantity<U, Rep>;
|
||||
};
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2, Scalar Rep>
|
||||
struct common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> {
|
||||
using type = quantity<D, downcasting_traits_t<unit<D, common_ratio<typename U1::ratio, typename U2::ratio>>>, Rep>;
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2, Scalar Rep>
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
struct common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> {
|
||||
using type = quantity<downcasting_traits_t<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>, Rep>;
|
||||
};
|
||||
|
||||
template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
|
||||
@@ -121,9 +121,9 @@ namespace units {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Quantity To, Dimension D, Unit U, Scalar Rep>
|
||||
requires std::Same<typename To::dimension, D>
|
||||
constexpr To quantity_cast(const quantity<D, U, Rep>& q)
|
||||
template<Quantity To, Unit U, Scalar Rep>
|
||||
requires std::Same<typename To::dimension, typename U::dimension>
|
||||
constexpr To quantity_cast(const quantity<U, Rep>& q)
|
||||
{
|
||||
using c_ratio = ratio_divide<typename U::ratio, typename To::unit::ratio>;
|
||||
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
|
||||
@@ -143,15 +143,14 @@ namespace units {
|
||||
|
||||
// quantity
|
||||
|
||||
template<Dimension D, Unit U, Scalar Rep>
|
||||
requires std::Same<D, typename U::dimension>
|
||||
template<Unit U, Scalar Rep = double>
|
||||
class quantity {
|
||||
Rep value_;
|
||||
|
||||
public:
|
||||
using dimension = D;
|
||||
using unit = U;
|
||||
using rep = Rep;
|
||||
using dimension = U::dimension;
|
||||
|
||||
static_assert(!Quantity<Rep>, "rep cannot be a quantity");
|
||||
|
||||
@@ -238,163 +237,173 @@ namespace units {
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator+(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator+(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
using common_rep = decltype(lhs.count() + rhs.count());
|
||||
using ret = common_quantity_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
|
||||
using ret = common_quantity_t<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
|
||||
return ret(ret(lhs).count() + ret(rhs).count());
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator-(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator-(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
using common_rep = decltype(lhs.count() - rhs.count());
|
||||
using ret = common_quantity_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
|
||||
using ret = common_quantity_t<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
|
||||
return ret(ret(lhs).count() - ret(rhs).count());
|
||||
}
|
||||
|
||||
// template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2>
|
||||
template<typename D, typename U, typename Rep1, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator*(const quantity<D, U, Rep1>& q,
|
||||
// template<Unit U, Scalar Rep1, Scalar Rep2>
|
||||
template<typename U, typename Rep1, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator*(const quantity<U, Rep1>& q,
|
||||
const Rep2& v)
|
||||
requires (!Quantity<Rep2>)
|
||||
{
|
||||
using common_rep = decltype(q.count()* v);
|
||||
using ret = quantity<D, U, common_rep>;
|
||||
using ret = quantity<U, common_rep>;
|
||||
return ret(ret(q).count() * v);
|
||||
}
|
||||
|
||||
//template<Scalar Rep1, Dimension D, Unit U, Scalar Rep2>
|
||||
template<typename Rep1, typename D, typename U, typename Rep2>
|
||||
//template<Scalar Rep1, Unit U, Scalar Rep2>
|
||||
template<typename Rep1, typename U, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator*(const Rep1& v,
|
||||
const quantity<D, U, Rep2>& q)
|
||||
const quantity<U, Rep2>& q)
|
||||
requires (!Quantity<Rep1>)
|
||||
{
|
||||
return q * v;
|
||||
}
|
||||
|
||||
template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator*(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator*(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs)
|
||||
requires treat_as_floating_point<decltype(lhs.count() * rhs.count())> ||
|
||||
(std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1)
|
||||
{
|
||||
using dim = dimension_multiply_t<D1, D2>;
|
||||
using dim = dimension_multiply_t<typename U1::dimension, typename U2::dimension>;
|
||||
using common_rep = decltype(lhs.count() * rhs.count());
|
||||
using ret = quantity<dim, downcasting_traits_t<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||
using ret = quantity<downcasting_traits_t<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||
return ret(lhs.count() * rhs.count());
|
||||
}
|
||||
|
||||
// template<Scalar Rep1, Dimension D, Unit U, Scalar Rep2>
|
||||
template<typename Rep1, typename D, typename U, typename Rep2>
|
||||
// template<Scalar Rep1, Unit U, Scalar Rep2>
|
||||
template<typename Rep1, typename U, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator/(const Rep1& v,
|
||||
const quantity<D, U, Rep2>& q)
|
||||
const quantity<U, Rep2>& q)
|
||||
requires (!Quantity<Rep1>)
|
||||
{
|
||||
Expects(q != std::remove_cvref_t<decltype(q)>(0));
|
||||
|
||||
using dim = dim_invert_t<D>;
|
||||
using dim = dim_invert_t<typename U::dimension>;
|
||||
using common_rep = decltype(v / q.count());
|
||||
using ret = quantity<dim, downcasting_traits_t<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
|
||||
using den = quantity<D, U, common_rep>;
|
||||
using ret = quantity<downcasting_traits_t<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
|
||||
using den = quantity<U, common_rep>;
|
||||
return ret(v / den(q).count());
|
||||
}
|
||||
|
||||
// template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2>
|
||||
template<typename D, typename U, typename Rep1, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator/(const quantity<D, U, Rep1>& q,
|
||||
// template<Unit U, Scalar Rep1, Scalar Rep2>
|
||||
template<typename U, typename Rep1, typename Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator/(const quantity<U, Rep1>& q,
|
||||
const Rep2& v)
|
||||
requires (!Quantity<Rep2>)
|
||||
{
|
||||
Expects(v != Rep2{0});
|
||||
|
||||
using common_rep = decltype(q.count() / v);
|
||||
using ret = quantity<D, U, common_rep>;
|
||||
using ret = quantity<U, common_rep>;
|
||||
return ret(ret(q).count() / v);
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Scalar operator/(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
|
||||
|
||||
using common_rep = decltype(lhs.count() / rhs.count());
|
||||
using cq = common_quantity_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
|
||||
using cq = common_quantity_t<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
|
||||
return cq(lhs).count() / cq(rhs).count();
|
||||
}
|
||||
|
||||
template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator/(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs)
|
||||
requires treat_as_floating_point<decltype(lhs.count() / rhs.count())> ||
|
||||
(ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator/(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs)
|
||||
requires (!std::Same<typename U1::dimension, typename U2::dimension>) &&
|
||||
(treat_as_floating_point<decltype(lhs.count() / rhs.count())> ||
|
||||
(ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1))
|
||||
{
|
||||
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
|
||||
|
||||
using common_rep = decltype(lhs.count() / rhs.count());
|
||||
using dim = dimension_divide_t<D1, D2>;
|
||||
using ret = quantity<dim, downcasting_traits_t<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||
using dim = dimension_divide_t<typename U1::dimension, typename U2::dimension>;
|
||||
using ret = quantity<downcasting_traits_t<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
|
||||
return ret(lhs.count() / rhs.count());
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator%(const quantity<D, U, Rep1>& q,
|
||||
template<Unit U, Scalar Rep1, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator%(const quantity<U, Rep1>& q,
|
||||
const Rep2& v)
|
||||
{
|
||||
using common_rep = decltype(q.count() % v);
|
||||
using ret = quantity<D, U, common_rep>;
|
||||
using ret = quantity<U, common_rep>;
|
||||
return ret(ret(q).count() % v);
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator%(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr Quantity operator%(const quantity<U1, Rep1>& lhs,
|
||||
const quantity<U2, Rep2>& rhs)
|
||||
{
|
||||
using common_rep = decltype(lhs.count() % rhs.count());
|
||||
using ret = common_quantity_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
|
||||
using ret = common_quantity_t<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
|
||||
return ret(ret(lhs).count() % ret(rhs).count());
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator==(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator==(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
using ct = common_quantity_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
using ct = common_quantity_t<quantity<U1, Rep1>, quantity<U2, Rep2>>;
|
||||
return ct(lhs).count() == ct(rhs).count();
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator!=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator!=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator<(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator<(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
using ct = common_quantity_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
using ct = common_quantity_t<quantity<U1, Rep1>, quantity<U2, Rep2>>;
|
||||
return ct(lhs).count() < ct(rhs).count();
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator<=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator<=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator>(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator>(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator>=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
|
||||
[[nodiscard]] constexpr bool operator>=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
|
||||
requires std::Same<typename U1::dimension, typename U2::dimension>
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
@@ -33,17 +33,14 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Substance = Quantity<T> && std::Same<typename T::dimension, dimension_substance>;
|
||||
|
||||
template<Unit U = struct mole, Number Rep = double>
|
||||
using substance = quantity<dimension_substance, U, Rep>;
|
||||
|
||||
struct mole : unit<dimension_substance> {};
|
||||
template<> struct downcasting_traits<downcast_from<mole>> : downcast_to<mole> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
// mol
|
||||
constexpr auto operator""_mol(unsigned long long l) { return substance<mole, std::int64_t>(l); }
|
||||
constexpr auto operator""_mol(long double l) { return substance<mole, long double>(l); }
|
||||
constexpr auto operator""_mol(unsigned long long l) { return quantity<mole, std::int64_t>(l); }
|
||||
constexpr auto operator""_mol(long double l) { return quantity<mole, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -33,17 +33,14 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool ThermodynamicTemperature = Quantity<T> && std::Same<typename T::dimension, dimension_temperature>;
|
||||
|
||||
template<Unit U = struct kelvin, Number Rep = double>
|
||||
using temperature = quantity<dimension_temperature, U, Rep>;
|
||||
|
||||
struct kelvin : unit<dimension_temperature> {};
|
||||
template<> struct downcasting_traits<downcast_from<kelvin>> : downcast_to<kelvin> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
// K
|
||||
constexpr auto operator""_K(unsigned long long l) { return temperature<kelvin, std::int64_t>(l); }
|
||||
constexpr auto operator""_K(long double l) { return temperature<kelvin, long double>(l); }
|
||||
constexpr auto operator""_K(unsigned long long l) { return quantity<kelvin, std::int64_t>(l); }
|
||||
constexpr auto operator""_K(long double l) { return quantity<kelvin, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -33,9 +33,6 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Time = Quantity<T> && std::Same<typename T::dimension, dimension_time>;
|
||||
|
||||
template<Unit U = struct second, Number Rep = double>
|
||||
using time = quantity<dimension_time, U, Rep>;
|
||||
|
||||
struct second : unit<dimension_time> {};
|
||||
template<> struct downcasting_traits<downcast_from<second>> : downcast_to<second> {};
|
||||
|
||||
@@ -57,28 +54,28 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// ns
|
||||
constexpr auto operator""_ns(unsigned long long l) { return time<nanosecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_ns(long double l) { return time<nanosecond, long double>(l); }
|
||||
constexpr auto operator""_ns(unsigned long long l) { return quantity<nanosecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_ns(long double l) { return quantity<nanosecond, long double>(l); }
|
||||
|
||||
// us
|
||||
constexpr auto operator""_us(unsigned long long l) { return time<microsecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_us(long double l) { return time<microsecond, long double>(l); }
|
||||
constexpr auto operator""_us(unsigned long long l) { return quantity<microsecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_us(long double l) { return quantity<microsecond, long double>(l); }
|
||||
|
||||
// ms
|
||||
constexpr auto operator""_ms(unsigned long long l) { return time<millisecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_ms(long double l) { return time<millisecond, long double>(l); }
|
||||
constexpr auto operator""_ms(unsigned long long l) { return quantity<millisecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_ms(long double l) { return quantity<millisecond, long double>(l); }
|
||||
|
||||
// s
|
||||
constexpr auto operator""_s(unsigned long long l) { return time<second, std::int64_t>(l); }
|
||||
constexpr auto operator""_s(long double l) { return time<second, long double>(l); }
|
||||
constexpr auto operator""_s(unsigned long long l) { return quantity<second, std::int64_t>(l); }
|
||||
constexpr auto operator""_s(long double l) { return quantity<second, long double>(l); }
|
||||
|
||||
// min
|
||||
constexpr auto operator""_min(unsigned long long l) { return time<minute, std::int64_t>(l); }
|
||||
constexpr auto operator""_min(long double l) { return time<minute, long double>(l); }
|
||||
constexpr auto operator""_min(unsigned long long l) { return quantity<minute, std::int64_t>(l); }
|
||||
constexpr auto operator""_min(long double l) { return quantity<minute, long double>(l); }
|
||||
|
||||
// h
|
||||
constexpr auto operator""_h(unsigned long long l) { return time<hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_h(long double l) { return time<hour, long double>(l); }
|
||||
constexpr auto operator""_h(unsigned long long l) { return quantity<hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_h(long double l) { return quantity<hour, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -33,9 +33,6 @@ namespace units {
|
||||
template<typename T>
|
||||
concept bool Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>;
|
||||
|
||||
template<Unit U = struct meter_per_second, Number Rep = double>
|
||||
using velocity = quantity<dimension_velocity, U, Rep>;
|
||||
|
||||
struct meter_per_second : derived_unit<dimension_velocity, meter, second> {};
|
||||
template<> struct downcasting_traits<downcast_from<meter_per_second>> : downcast_to<meter_per_second> {};
|
||||
|
||||
@@ -48,16 +45,16 @@ namespace units {
|
||||
inline namespace literals {
|
||||
|
||||
// mps
|
||||
constexpr auto operator""_mps(unsigned long long l) { return velocity<meter_per_second, std::int64_t>(l); }
|
||||
constexpr auto operator""_mps(long double l) { return velocity<meter_per_second, long double>(l); }
|
||||
constexpr auto operator""_mps(unsigned long long l) { return quantity<meter_per_second, std::int64_t>(l); }
|
||||
constexpr auto operator""_mps(long double l) { return quantity<meter_per_second, long double>(l); }
|
||||
|
||||
// kmph
|
||||
constexpr auto operator""_kmph(unsigned long long l) { return velocity<kilometer_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_kmph(long double l) { return velocity<kilometer_per_hour, long double>(l); }
|
||||
constexpr auto operator""_kmph(unsigned long long l) { return quantity<kilometer_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_kmph(long double l) { return quantity<kilometer_per_hour, long double>(l); }
|
||||
|
||||
// mph
|
||||
constexpr auto operator""_mph(unsigned long long l) { return velocity<mile_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_mph(long double l) { return velocity<mile_per_hour, long double>(l); }
|
||||
constexpr auto operator""_mph(unsigned long long l) { return quantity<mile_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_mph(long double l) { return quantity<mile_per_hour, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@@ -77,76 +77,76 @@ namespace {
|
||||
// class invariants
|
||||
|
||||
// constexpr quantity<dimension_length, second, int> q; // should a static_assert
|
||||
// constexpr quantity<dimension_length, meter, length<meter, int>> error(0_m); // should trigger a static_assert
|
||||
// constexpr quantity<dimension_length, meter, quantity<meter, int>> error(0_m); // should trigger a static_assert
|
||||
// constexpr quantity<int, int, double> error(0); // should trigger a static_assert
|
||||
// constexpr quantity<dimension_length, unit<dimension_length, std::ratio<-1, 1>>, int> error(0); // should trigger a static_assert
|
||||
|
||||
// member types
|
||||
|
||||
static_assert(std::is_same_v<length<meter, int>::rep, int>);
|
||||
static_assert(std::is_same_v<length<meter, double>::rep, double>);
|
||||
static_assert(std::is_same_v<length<meter, int>::unit, meter>);
|
||||
static_assert(std::is_same_v<length<kilometer, int>::unit, kilometer>);
|
||||
static_assert(std::is_same_v<quantity<meter, int>::rep, int>);
|
||||
static_assert(std::is_same_v<quantity<meter, double>::rep, double>);
|
||||
static_assert(std::is_same_v<quantity<meter, int>::unit, meter>);
|
||||
static_assert(std::is_same_v<quantity<kilometer, int>::unit, kilometer>);
|
||||
|
||||
// constructors
|
||||
|
||||
static_assert(length<meter, int>().count() == 0);
|
||||
constexpr length<meter, int> km{1000};
|
||||
static_assert(quantity<meter, int>().count() == 0);
|
||||
constexpr quantity<meter, int> km{1000};
|
||||
static_assert(km.count() == 1000);
|
||||
static_assert(length<meter, int>(km).count() == km.count());
|
||||
static_assert(quantity<meter, int>(km).count() == km.count());
|
||||
|
||||
static_assert(length<meter, int>(1).count() == 1);
|
||||
static_assert(length<meter, int>(my_value(1)).count() == 1);
|
||||
static_assert(length<meter, my_value<int>>(1).count() == 1);
|
||||
// static_assert(length<meter, int>(1.0).count() == 1); // should not compile
|
||||
// static_assert(length<meter, int>(my_value(1.0)).count() == 1); // should not compile
|
||||
// static_assert(length<meter, my_value>(1.0).count() == 1); // should not compile
|
||||
static_assert(length<meter, double>(1.0).count() == 1.0);
|
||||
static_assert(length<meter, double>(my_value(1.0)).count() == 1.0);
|
||||
static_assert(length<meter, double>(1).count() == 1.0);
|
||||
static_assert(length<meter, double>(my_value(1)).count() == 1.0);
|
||||
static_assert(length<meter, double>(3.14).count() == 3.14);
|
||||
static_assert(length<meter, my_value<double>>(1.0).count() == 1.0);
|
||||
static_assert(length<meter, my_value<double>>(1).count() == 1.0);
|
||||
static_assert(length<meter, my_value<double>>(3.14).count() == 3.14);
|
||||
static_assert(quantity<meter, int>(1).count() == 1);
|
||||
static_assert(quantity<meter, int>(my_value(1)).count() == 1);
|
||||
static_assert(quantity<meter, my_value<int>>(1).count() == 1);
|
||||
// static_assert(quantity<meter, int>(1.0).count() == 1); // should not compile
|
||||
// static_assert(quantity<meter, int>(my_value(1.0)).count() == 1); // should not compile
|
||||
// static_assert(quantity<meter, my_value>(1.0).count() == 1); // should not compile
|
||||
static_assert(quantity<meter, double>(1.0).count() == 1.0);
|
||||
static_assert(quantity<meter, double>(my_value(1.0)).count() == 1.0);
|
||||
static_assert(quantity<meter, double>(1).count() == 1.0);
|
||||
static_assert(quantity<meter, double>(my_value(1)).count() == 1.0);
|
||||
static_assert(quantity<meter, double>(3.14).count() == 3.14);
|
||||
static_assert(quantity<meter, my_value<double>>(1.0).count() == 1.0);
|
||||
static_assert(quantity<meter, my_value<double>>(1).count() == 1.0);
|
||||
static_assert(quantity<meter, my_value<double>>(3.14).count() == 3.14);
|
||||
|
||||
static_assert(length<meter, int>(km).count() == 1000);
|
||||
// static_assert(length<meter, int>(length<meter, double>(3.14)).count() == 3); // should not compile
|
||||
static_assert(length<meter, int>(quantity_cast<length<meter, my_value<int>>>(3.14_m)).count() == 3);
|
||||
// static_assert(length<meter, int>(length<meter, my_value<double>>(1000.0)).count() == 1000); // should not compile
|
||||
// static_assert(length<meter, my_value>(1000.0_m).count() == 1000); // should not compile
|
||||
static_assert(length<meter, double>(1000.0_m).count() == 1000.0);
|
||||
static_assert(length<meter, double>(length<meter, my_value<double>>(1000.0)).count() == 1000.0);
|
||||
static_assert(length<meter, my_value<double>>(1000.0_m).count() == 1000.0);
|
||||
static_assert(length<meter, double>(km).count() == 1000.0);
|
||||
static_assert(length<meter, my_value<double>>(km).count() == 1000.0);
|
||||
static_assert(length<meter, int>(1_km).count() == 1000);
|
||||
// static_assert(length<meter, int>(1_s).count() == 1); // should not compile
|
||||
// static_assert(length<kilometer, int>(1010_m).count() == 1); // should not compile
|
||||
static_assert(length<kilometer, int>(quantity_cast<length<kilometer, my_value<int>>>(1010_m)).count() == 1);
|
||||
static_assert(quantity<meter, int>(km).count() == 1000);
|
||||
// static_assert(quantity<meter, int>(quantity<meter, double>(3.14)).count() == 3); // should not compile
|
||||
static_assert(quantity<meter, int>(quantity_cast<quantity<meter, my_value<int>>>(3.14_m)).count() == 3);
|
||||
// static_assert(quantity<meter, int>(quantity<meter, my_value<double>>(1000.0)).count() == 1000); // should not compile
|
||||
// static_assert(quantity<meter, my_value>(1000.0_m).count() == 1000); // should not compile
|
||||
static_assert(quantity<meter, double>(1000.0_m).count() == 1000.0);
|
||||
static_assert(quantity<meter, double>(quantity<meter, my_value<double>>(1000.0)).count() == 1000.0);
|
||||
static_assert(quantity<meter, my_value<double>>(1000.0_m).count() == 1000.0);
|
||||
static_assert(quantity<meter, double>(km).count() == 1000.0);
|
||||
static_assert(quantity<meter, my_value<double>>(km).count() == 1000.0);
|
||||
static_assert(quantity<meter, int>(1_km).count() == 1000);
|
||||
// static_assert(quantity<meter, int>(1_s).count() == 1); // should not compile
|
||||
// static_assert(quantity<kilometer, int>(1010_m).count() == 1); // should not compile
|
||||
static_assert(quantity<kilometer, int>(quantity_cast<quantity<kilometer, my_value<int>>>(1010_m)).count() == 1);
|
||||
|
||||
// assignment operator
|
||||
|
||||
static_assert([]() {
|
||||
length<meter, int> l1(1), l2(2);
|
||||
quantity<meter, int> l1(1), l2(2);
|
||||
return l2 = l1;
|
||||
}()
|
||||
.count() == 1);
|
||||
|
||||
// static member functions
|
||||
|
||||
static_assert(length<meter, int>::zero().count() == 0);
|
||||
static_assert(length<meter, int>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(length<meter, int>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(length<meter, double>::zero().count() == 0.0);
|
||||
static_assert(length<meter, double>::min().count() == std::numeric_limits<double>::lowest());
|
||||
static_assert(length<meter, double>::max().count() == std::numeric_limits<double>::max());
|
||||
static_assert(length<meter, my_value<int>>::zero().count() == 0);
|
||||
static_assert(length<meter, my_value<int>>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(length<meter, my_value<int>>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(length<meter, my_value<double>>::zero().count() == 0.0);
|
||||
static_assert(length<meter, my_value<double>>::min().count() == std::numeric_limits<double>::lowest());
|
||||
static_assert(length<meter, my_value<double>>::max().count() == std::numeric_limits<double>::max());
|
||||
static_assert(quantity<meter, int>::zero().count() == 0);
|
||||
static_assert(quantity<meter, int>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(quantity<meter, int>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(quantity<meter, double>::zero().count() == 0.0);
|
||||
static_assert(quantity<meter, double>::min().count() == std::numeric_limits<double>::lowest());
|
||||
static_assert(quantity<meter, double>::max().count() == std::numeric_limits<double>::max());
|
||||
static_assert(quantity<meter, my_value<int>>::zero().count() == 0);
|
||||
static_assert(quantity<meter, my_value<int>>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(quantity<meter, my_value<int>>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(quantity<meter, my_value<double>>::zero().count() == 0.0);
|
||||
static_assert(quantity<meter, my_value<double>>::min().count() == std::numeric_limits<double>::lowest());
|
||||
static_assert(quantity<meter, my_value<double>>::max().count() == std::numeric_limits<double>::max());
|
||||
|
||||
// unary member operators
|
||||
|
||||
@@ -160,19 +160,19 @@ namespace {
|
||||
static_assert([](auto v) {
|
||||
auto vv = v++;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<meter, int>(1001), length<meter, int>(1000)));
|
||||
}(km) == std::make_pair(quantity<meter, int>(1001), quantity<meter, int>(1000)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = ++v;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<meter, int>(1001), length<meter, int>(1001)));
|
||||
}(km) == std::make_pair(quantity<meter, int>(1001), quantity<meter, int>(1001)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = v--;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<meter, int>(999), length<meter, int>(1000)));
|
||||
}(km) == std::make_pair(quantity<meter, int>(999), quantity<meter, int>(1000)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = --v;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<meter, int>(999), length<meter, int>(999)));
|
||||
}(km) == std::make_pair(quantity<meter, int>(999), quantity<meter, int>(999)));
|
||||
|
||||
// compound assignment
|
||||
|
||||
@@ -185,21 +185,21 @@ namespace {
|
||||
|
||||
// non-member arithmetic operators
|
||||
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() + length<meter, double>()), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() + length<meter, double>()), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<kilometer, int>() + length<meter, double>()), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, double>() - length<meter, int>()), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<kilometer, double>() - length<meter, int>()), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() * 1.0), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(1.0 * length<meter, int>()), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(velocity<meter_per_second, int>() * units::time<second, int>()), quantity<dimension_length, units::meter, int>>);
|
||||
static_assert(std::is_same_v<decltype(1 / units::time<second, int>()), quantity<dimension_frequency, hertz, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() / 1.0), quantity<dimension_length, meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() / length<meter, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(length<kilometer, int>() / length<meter, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() / units::time<second, int>()), quantity<dimension_velocity, meter_per_second, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() % short(1)), quantity<dimension_length, meter, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() % length<meter, short>(1)), quantity<dimension_length, meter, int>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() + quantity<meter, double>()), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() + quantity<meter, double>()), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<kilometer, int>() + quantity<meter, double>()), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, double>() - quantity<meter, int>()), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<kilometer, double>() - quantity<meter, int>()), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() * 1.0), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(1.0 * quantity<meter, int>()), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter_per_second, int>() * units::quantity<second, int>()), quantity<units::meter, int>>);
|
||||
static_assert(std::is_same_v<decltype(1 / units::quantity<second, int>()), quantity<hertz, int>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() / 1.0), quantity<meter, double>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() / quantity<meter, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(quantity<kilometer, int>() / quantity<meter, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() / units::quantity<second, int>()), quantity<meter_per_second, int>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() % short(1)), quantity<meter, int>>);
|
||||
static_assert(std::is_same_v<decltype(quantity<meter, int>() % quantity<meter, short>(1)), quantity<meter, int>>);
|
||||
|
||||
static_assert((1_m + km).count() == 1001);
|
||||
static_assert((1_m + 1_km).count() == 1001);
|
||||
@@ -247,19 +247,19 @@ namespace {
|
||||
|
||||
// is_quantity
|
||||
|
||||
static_assert(Quantity<length<millimeter, int>>);
|
||||
static_assert(Quantity<quantity<millimeter, int>>);
|
||||
|
||||
// common_quantity
|
||||
|
||||
static_assert(std::is_same_v<common_quantity_t<length<meter, int>, length<kilometer, int>>, length<meter, int>>);
|
||||
static_assert(std::is_same_v<common_quantity_t<length<kilometer, long long>, length<meter, int>>, length<meter, long long>>);
|
||||
static_assert(std::is_same_v<common_quantity_t<length<kilometer, long long>, length<millimeter, double>>, length<millimeter, double>>);
|
||||
static_assert(std::is_same_v<common_quantity_t<quantity<meter, int>, quantity<kilometer, int>>, quantity<meter, int>>);
|
||||
static_assert(std::is_same_v<common_quantity_t<quantity<kilometer, long long>, quantity<meter, int>>, quantity<meter, long long>>);
|
||||
static_assert(std::is_same_v<common_quantity_t<quantity<kilometer, long long>, quantity<millimeter, double>>, quantity<millimeter, double>>);
|
||||
|
||||
// quantity_cast
|
||||
|
||||
// static_assert(quantity_cast<int>(2_km).count() == 2000); // should not compile
|
||||
static_assert(quantity_cast<length<meter, int>>(2_km).count() == 2000);
|
||||
static_assert(quantity_cast<length<kilometer, int>>(2000_m).count() == 2);
|
||||
static_assert(quantity_cast<quantity<meter, int>>(2_km).count() == 2000);
|
||||
static_assert(quantity_cast<quantity<kilometer, int>>(2000_m).count() == 2);
|
||||
|
||||
// time
|
||||
|
||||
|
@@ -74,7 +74,7 @@ namespace {
|
||||
|
||||
// velocity
|
||||
|
||||
static_assert(std::is_same_v<decltype(1_km / 1_s), velocity<unit<dimension_velocity, ratio<1000, 1>>, std::int64_t>>);
|
||||
static_assert(std::is_same_v<decltype(1_km / 1_s), quantity<unit<dimension_velocity, ratio<1000, 1>>, std::int64_t>>);
|
||||
|
||||
static_assert(10_m / 5_s == 2_mps);
|
||||
static_assert(10 / 5_s * 1_m == 2_mps);
|
||||
@@ -92,7 +92,7 @@ namespace {
|
||||
|
||||
static_assert(2_km / 2_kmph == 1_h);
|
||||
// static_assert(2000_m / 2_kmph == 1_h); // should not compile
|
||||
static_assert(quantity_cast<length<kilometer, int>>(2000_m) / 2_kmph == 1_h);
|
||||
static_assert(quantity_cast<quantity<kilometer, int>>(2000_m) / 2_kmph == 1_h);
|
||||
|
||||
// area
|
||||
|
||||
|
Reference in New Issue
Block a user