Dimension template parameter removed from quantity

This commit is contained in:
Mateusz Pusz
2019-07-19 13:49:49 +02:00
parent 03a22cba2a
commit eeb4c9c951
16 changed files with 328 additions and 409 deletions

View File

@@ -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: Quantity is a concrete amount of a unit for a specified dimension with a specific representation:
```cpp ```cpp
units::quantity<units::dimension_length, units::kilometer, double> d1(123); units::quantity<units::kilometer, double> d1(123);
auto d2 = 123_km; // units::quantity<units::dimension_length, units::kilometer, std::int64_t> auto d2 = 123_km; // units::quantity<units::kilometer, std::int64_t>
``` ```
There are helper aliases provided to improve the work with quantities: There are C++ concepts provided for each such quantity type:
```
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:
```cpp ```cpp
template<typename T> template<typename T>
@@ -241,8 +231,7 @@ concept Unit =
expressed in a specific unit of that dimension: expressed in a specific unit of that dimension:
```cpp ```cpp
template<Dimension D, Unit U, Number Rep> template<Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity; class quantity;
``` ```
@@ -259,29 +248,36 @@ concept Quantity =
member types and functions as below: member types and functions as below:
```cpp ```cpp
template<Dimension D, Unit U, Number Rep> template<Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity { class quantity {
public: public:
using dimension = D;
using unit = U; using unit = U;
using rep = Rep;
using dimension = U::dimension;
template<Dimension D1, Unit U1, Number Rep1, Dimension D2, Unit U2, Number Rep2> [[nodiscard]] static constexpr quantity one() noexcept { return quantity(quantity_values<Rep>::one()); }
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);
template<Number Rep1, Dimension D, Unit U, Number Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar 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>> requires treat_as_floating_point<decltype(lhs.count() * rhs.count())> ||
constexpr operator/(const Rep1& v, (std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1)
const quantity<D, U, Rep2>& q) [[expects: q != quantity<D, U, Rep2>(0)]]; [[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> template<Scalar Rep1, typename U, typename Rep2>
requires treat_as_floating_point<std::common_type_t<Rep1, Rep2>> || std::ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1 [[nodiscard]] constexpr Quantity operator/(const Rep1& v,
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>> const quantity<U, Rep2>& q)
constexpr operator/(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs) [[expects: rhs != quantity<D, U2, Rep2>(0)]]; 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: For example with template aliases usage the following code:
```cpp ```cpp
const Velocity t = 20_s; const Velocity auto t = 20_s;
``` ```
could generate a following compile time error: could generate a following compile time error:
```text ```text
C:\repos\units\example\example.cpp:39:22: error: deduced initializer does not satisfy placeholder constraints <path>\example\example.cpp:39:22: error: deduced initializer does not satisfy placeholder constraints
const Velocity t = 20_s; const Velocity auto t = 20_s;
^~~~ ^~~~
In file included from C:\repos\units\example\example.cpp:23: In file included from <path>\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>/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>; 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, In file included from <path>/src/include/units/bits/tools.h:25,
from C:/repos/units/src/include/units/dimension.h:25, from <path>/src/include/units/dimension.h:25,
from C:/repos/units/src/include/units/si/base_dimensions.h:25, from <path>/src/include/units/si/base_dimensions.h:25,
from C:/repos/units/src/include/units/si/velocity.h:25, from <path>/src/include/units/si/velocity.h:25,
from C:\repos\units\example\example.cpp:23: from <path>\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> >]' <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>; 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 Time and velocity are not that complicated dimensions and there are much more complicated dimensions
out there, but even for those dimensions out there, but even for those dimensions
```text ```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 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: same code will result with such an error:
```text ```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; const Velocity t = 20_s;
^~~~ ^~~~
In file included from C:\repos\units\example\example.cpp:23: In file included from <path>\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>]' <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>; 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, In file included from <path>/src/include/units/bits/tools.h:25,
from C:/repos/units/src/include/units/dimension.h:25, from <path>/src/include/units/dimension.h:25,
from C:/repos/units/src/include/units/si/base_dimensions.h:25, from <path>/src/include/units/si/base_dimensions.h:25,
from C:/repos/units/src/include/units/si/velocity.h:25, from <path>/src/include/units/si/velocity.h:25,
from C:\repos\units\example\example.cpp:23: from <path>\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]' <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>; 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 Now
```text ```text
[with T = units::quantity<units::dimension_time, units::second, long long int>] [with T = units::quantity<units::second, long long int>]
``` ```
and and
@@ -383,20 +379,32 @@ and
are not arguably much easier to understand thus provide better user experience. 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. `base_type` member type in `downcast_base` class template.
```cpp ```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> template<Downcastable T>
using downcast_from = T::base_type; using downcast_from = T::base_type;
template<typename T> template<Downcastable T>
using downcast_to = std::type_identity<T>; using downcast_to = std::type_identity<T>;
template<typename T> template<Downcastable T>
struct downcasting_traits : downcast_to<T> {}; struct downcasting_traits : downcast_to<T> {};
template<typename T> template<Downcastable T>
using downcasting_traits_t = downcasting_traits<T>::type; 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> {}; 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: 2. Define a concept that will match a new dimension:
```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:
```cpp ```cpp
template<typename T> template<typename T>
concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>; 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 - base unit
@@ -465,11 +466,11 @@ template<> struct downcasting_traits<downcast_from<kilometer_per_hour>> : downca
```cpp ```cpp
inline namespace literals { inline namespace literals {
constexpr auto operator""_mps(unsigned long long l) { return velocity<meter_per_second, std::int64_t>(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 velocity<meter_per_second, long double>(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(unsigned long long l) { return quantity<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(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? 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 5. What is the best way to add support for temperatures?
`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. Should we provide `seconds<int>` or stay with `time<second, int>`? What about CTAD problem Temperature absolute values not only require `std::ratio` but also should be adjusted/shifted
for `units::length<units::mile> d3(3);`? 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 7. Should we provide cmath-like functions for quantities?
constant values (i.e. [°C] = [K] 273.15).
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 9. Should we require explicit casts (i.e. quantity_cast) between different systems of
as they provide different ratio values rather than types? measurement?
In example instead: 10. Should we support integral representations?
```cpp 11. Provide ostream overloads to print quantity units (use `std::format`)?
struct celsius : unit<dimension_temperature, convert<offset<-27315, 100>>> {};
```
we could think about something like: 12. Should we provide support for dimensionless quantities?
```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?
Because dimensionless quantities have no associated units, they behave as normal scalars, 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 and allow implicit conversion to and from the underlying value type or types that are
convertible to/from that value type. convertible to/from that value type.
17. Should we leave `quantity` and specific dimensions as 13. Should we standardize accompany tools (`downcasting_traits`, `type_list` operations, `common_ratio`, etc)?
```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.
14. Do we need to support fractional exponents (i.e. `dimension<exp<"length", 2, 3>>` as 2/3)?

View File

@@ -38,13 +38,13 @@ void example_1(V v, T t)
{ {
const units::Length distance = v * 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 " 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) void example_2(double distance_v, double duration_v)
{ {
units::length<units::kilometer> distance(distance_v); units::quantity<units::kilometer> distance(distance_v);
units::time<units::hour> duration(duration_v); units::quantity<units::hour> duration(duration_v);
const auto kmph = avg_speed(distance, duration); const auto kmph = avg_speed(distance, duration);
std::cout << "Average speed of a car that makes " << distance.count() << " km in " std::cout << "Average speed of a car that makes " << distance.count() << " km in "
<< duration.count() << " hours is " << kmph.count() << " km/h.\n"; << duration.count() << " hours is " << kmph.count() << " km/h.\n";

View File

@@ -32,9 +32,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Area = Quantity<T> && std::Same<typename T::dimension, dimension_area>; 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> {}; struct square_millimeter : derived_unit<dimension_area, millimeter> {};
template<> struct downcasting_traits<downcast_from<square_millimeter>> : downcast_to<square_millimeter> {}; template<> struct downcasting_traits<downcast_from<square_millimeter>> : downcast_to<square_millimeter> {};
@@ -53,20 +50,20 @@ namespace units {
inline namespace literals { inline namespace literals {
// sq_mm // sq_mm
constexpr auto operator""_sq_mm(unsigned long long l) { return area<square_millimeter, std::int64_t>(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 area<square_millimeter, long double>(l); } constexpr auto operator""_sq_mm(long double l) { return quantity<square_millimeter, long double>(l); }
// sq_cm // sq_cm
constexpr auto operator""_sq_cm(unsigned long long l) { return area<square_centimeter, std::int64_t>(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 area<square_centimeter, long double>(l); } constexpr auto operator""_sq_cm(long double l) { return quantity<square_centimeter, long double>(l); }
// sq_m // sq_m
constexpr auto operator""_sq_m(unsigned long long l) { return area<square_meter, std::int64_t>(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 area<square_meter, long double>(l); } constexpr auto operator""_sq_m(long double l) { return quantity<square_meter, long double>(l); }
// sq_km // sq_km
constexpr auto operator""_sq_km(unsigned long long l) { return area<square_kilometer, std::int64_t>(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 area<square_kilometer, long double>(l); } constexpr auto operator""_sq_km(long double l) { return quantity<square_kilometer, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -37,6 +37,7 @@ namespace std {
using type_identity_t = typename type_identity<T>::type; using type_identity_t = typename type_identity<T>::type;
#endif // UNITS_HAS_STD_TYPE_IDENTITY #endif // UNITS_HAS_STD_TYPE_IDENTITY
// concepts // concepts
using experimental::ranges::Same; using experimental::ranges::Same;
using experimental::ranges::Integral; using experimental::ranges::Integral;

View File

@@ -33,17 +33,14 @@ namespace units {
template<typename T> template<typename T>
concept bool Current = Quantity<T> && std::Same<typename T::dimension, dimension_current>; 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> {}; struct ampere : unit<dimension_current> {};
template<> struct downcasting_traits<downcast_from<ampere>> : downcast_to<ampere> {}; template<> struct downcasting_traits<downcast_from<ampere>> : downcast_to<ampere> {};
inline namespace literals { inline namespace literals {
// A // A
constexpr auto operator""_A(unsigned long long l) { return current<ampere, std::int64_t>(l); } constexpr auto operator""_A(unsigned long long l) { return quantity<ampere, std::int64_t>(l); }
constexpr auto operator""_A(long double l) { return current<ampere, long double>(l); } constexpr auto operator""_A(long double l) { return quantity<ampere, long double>(l); }
} }

View File

@@ -33,9 +33,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Frequency = Quantity<T> && std::Same<typename T::dimension, dimension_frequency>; 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> {}; struct hertz : derived_unit<dimension_frequency, second> {};
template<> struct downcasting_traits<downcast_from<hertz>> : downcast_to<hertz> {}; template<> struct downcasting_traits<downcast_from<hertz>> : downcast_to<hertz> {};
@@ -57,28 +54,28 @@ namespace units {
inline namespace literals { inline namespace literals {
// mHz // mHz
constexpr auto operator""_mHz(unsigned long long l) { return frequency<millihertz, std::int64_t>(l); } constexpr auto operator""_mHz(unsigned long long l) { return quantity<millihertz, std::int64_t>(l); }
constexpr auto operator""_mHz(long double l) { return frequency<millihertz, long double>(l); } constexpr auto operator""_mHz(long double l) { return quantity<millihertz, long double>(l); }
// Hz // Hz
constexpr auto operator""_Hz(unsigned long long l) { return frequency<hertz, std::int64_t>(l); } constexpr auto operator""_Hz(unsigned long long l) { return quantity<hertz, std::int64_t>(l); }
constexpr auto operator""_Hz(long double l) { return frequency<hertz, long double>(l); } constexpr auto operator""_Hz(long double l) { return quantity<hertz, long double>(l); }
// kHz // kHz
constexpr auto operator""_kHz(unsigned long long l) { return frequency<kilohertz, std::int64_t>(l); } constexpr auto operator""_kHz(unsigned long long l) { return quantity<kilohertz, std::int64_t>(l); }
constexpr auto operator""_kHz(long double l) { return frequency<kilohertz, long double>(l); } constexpr auto operator""_kHz(long double l) { return quantity<kilohertz, long double>(l); }
// MHz // MHz
constexpr auto operator""_MHz(unsigned long long l) { return frequency<megahertz, std::int64_t>(l); } constexpr auto operator""_MHz(unsigned long long l) { return quantity<megahertz, std::int64_t>(l); }
constexpr auto operator""_MHz(long double l) { return frequency<megahertz, long double>(l); } constexpr auto operator""_MHz(long double l) { return quantity<megahertz, long double>(l); }
// GHz // GHz
constexpr auto operator""_GHz(unsigned long long l) { return frequency<gigahertz, std::int64_t>(l); } constexpr auto operator""_GHz(unsigned long long l) { return quantity<gigahertz, std::int64_t>(l); }
constexpr auto operator""_GHz(long double l) { return frequency<gigahertz, long double>(l); } constexpr auto operator""_GHz(long double l) { return quantity<gigahertz, long double>(l); }
// THz // THz
constexpr auto operator""_THz(unsigned long long l) { return frequency<terahertz, std::int64_t>(l); } constexpr auto operator""_THz(unsigned long long l) { return quantity<terahertz, std::int64_t>(l); }
constexpr auto operator""_THz(long double l) { return frequency<terahertz, long double>(l); } constexpr auto operator""_THz(long double l) { return quantity<terahertz, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -33,9 +33,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Length = Quantity<T> && std::Same<typename T::dimension, dimension_length>; 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 // SI units
struct meter : unit<dimension_length> {}; struct meter : unit<dimension_length> {};
template<> struct downcasting_traits<downcast_from<meter>> : downcast_to<meter> {}; template<> struct downcasting_traits<downcast_from<meter>> : downcast_to<meter> {};
@@ -52,20 +49,20 @@ namespace units {
inline namespace literals { inline namespace literals {
// mm // mm
constexpr auto operator""_mm(unsigned long long l) { return length<millimeter, std::int64_t>(l); } constexpr auto operator""_mm(unsigned long long l) { return quantity<millimeter, std::int64_t>(l); }
constexpr auto operator""_mm(long double l) { return length<millimeter, long double>(l); } constexpr auto operator""_mm(long double l) { return quantity<millimeter, long double>(l); }
// cm // cm
constexpr auto operator""_cm(unsigned long long l) { return length<centimeter, std::int64_t>(l); } constexpr auto operator""_cm(unsigned long long l) { return quantity<centimeter, std::int64_t>(l); }
constexpr auto operator""_cm(long double l) { return length<centimeter, long double>(l); } constexpr auto operator""_cm(long double l) { return quantity<centimeter, long double>(l); }
// m // m
constexpr auto operator""_m(unsigned long long l) { return length<meter, std::int64_t>(l); } constexpr auto operator""_m(unsigned long long l) { return quantity<meter, std::int64_t>(l); }
constexpr auto operator""_m(long double l) { return length<meter, long double>(l); } constexpr auto operator""_m(long double l) { return quantity<meter, long double>(l); }
// km // km
constexpr auto operator""_km(unsigned long long l) { return length<kilometer, std::int64_t>(l); } constexpr auto operator""_km(unsigned long long l) { return quantity<kilometer, std::int64_t>(l); }
constexpr auto operator""_km(long double l) { return length<kilometer, long double>(l); } constexpr auto operator""_km(long double l) { return quantity<kilometer, long double>(l); }
} // namespace literals } // namespace literals
@@ -85,20 +82,20 @@ namespace units {
inline namespace literals { inline namespace literals {
// yd // yd
constexpr auto operator""_yd(unsigned long long l) { return length<yard, std::int64_t>(l); } constexpr auto operator""_yd(unsigned long long l) { return quantity<yard, std::int64_t>(l); }
constexpr auto operator""_yd(long double l) { return length<yard, long double>(l); } constexpr auto operator""_yd(long double l) { return quantity<yard, long double>(l); }
// ft // ft
constexpr auto operator""_ft(unsigned long long l) { return length<foot, std::int64_t>(l); } constexpr auto operator""_ft(unsigned long long l) { return quantity<foot, std::int64_t>(l); }
constexpr auto operator""_ft(long double l) { return length<foot, long double>(l); } constexpr auto operator""_ft(long double l) { return quantity<foot, long double>(l); }
// in // in
constexpr auto operator""_in(unsigned long long l) { return length<inch, std::int64_t>(l); } constexpr auto operator""_in(unsigned long long l) { return quantity<inch, std::int64_t>(l); }
constexpr auto operator""_in(long double l) { return length<inch, long double>(l); } constexpr auto operator""_in(long double l) { return quantity<inch, long double>(l); }
// mi // mi
constexpr auto operator""_mi(unsigned long long l) { return length<mile, std::int64_t>(l); } constexpr auto operator""_mi(unsigned long long l) { return quantity<mile, std::int64_t>(l); }
constexpr auto operator""_mi(long double l) { return length<mile, long double>(l); } constexpr auto operator""_mi(long double l) { return quantity<mile, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -33,17 +33,14 @@ namespace units {
template<typename T> template<typename T>
concept bool LuminousIntensity = Quantity<T> && std::Same<typename T::dimension, dimension_luminous_intensity>; 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> {}; struct candela : unit<dimension_luminous_intensity> {};
template<> struct downcasting_traits<downcast_from<candela>> : downcast_to<candela> {}; template<> struct downcasting_traits<downcast_from<candela>> : downcast_to<candela> {};
inline namespace literals { inline namespace literals {
// cd // cd
constexpr auto operator""_cd(unsigned long long l) { return luminous_intensity<candela, std::int64_t>(l); } constexpr auto operator""_cd(unsigned long long l) { return quantity<candela, std::int64_t>(l); }
constexpr auto operator""_cd(long double l) { return luminous_intensity<candela, long double>(l); } constexpr auto operator""_cd(long double l) { return quantity<candela, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -33,9 +33,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Mass = Quantity<T> && std::Same<typename T::dimension, dimension_mass>; 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>> {}; struct gram : unit<dimension_mass, ratio<1, 1000>> {};
template<> struct downcasting_traits<downcast_from<gram>> : downcast_to<gram> {}; template<> struct downcasting_traits<downcast_from<gram>> : downcast_to<gram> {};
@@ -45,12 +42,12 @@ namespace units {
inline namespace literals { inline namespace literals {
// g // g
constexpr auto operator""_g(unsigned long long l) { return mass<gram, std::int64_t>(l); } constexpr auto operator""_g(unsigned long long l) { return quantity<gram, std::int64_t>(l); }
constexpr auto operator""_g(long double l) { return mass<gram, long double>(l); } constexpr auto operator""_g(long double l) { return quantity<gram, long double>(l); }
// kg // kg
constexpr auto operator""_kg(unsigned long long l) { return mass<kilogram, std::int64_t>(l); } constexpr auto operator""_kg(unsigned long long l) { return quantity<kilogram, std::int64_t>(l); }
constexpr auto operator""_kg(long double l) { return mass<kilogram, long double>(l); } constexpr auto operator""_kg(long double l) { return quantity<kilogram, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -45,14 +45,13 @@ namespace units {
template<typename T> template<typename T>
concept bool Scalar = Number<T> && !Quantity<T>; concept bool Scalar = Number<T> && !Quantity<T>;
template<Dimension D, Unit U, Scalar Rep> template<Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity; class quantity;
namespace detail { namespace detail {
template<Dimension D, Unit U, Scalar Rep> template<Unit U, Scalar Rep>
inline constexpr bool is_quantity<quantity<D, U, Rep>> = true; inline constexpr bool is_quantity<quantity<U, Rep>> = true;
} // namespace detail } // namespace detail
@@ -60,14 +59,15 @@ namespace units {
template<Quantity Q1, Quantity Q2, Scalar Rep> template<Quantity Q1, Quantity Q2, Scalar Rep>
struct common_quantity; struct common_quantity;
template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2, Scalar Rep> template<Unit U, Scalar Rep1, Scalar Rep2, Scalar Rep>
struct common_quantity<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> { struct common_quantity<quantity<U, Rep1>, quantity<U, Rep2>, Rep> {
using type = quantity<D, U, Rep>; using type = quantity<U, Rep>;
}; };
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2, Scalar Rep> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2, Scalar Rep>
struct common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> { requires std::Same<typename U1::dimension, typename U2::dimension>
using type = quantity<D, downcasting_traits_t<unit<D, common_ratio<typename U1::ratio, typename U2::ratio>>>, Rep>; 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>> 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 } // namespace detail
template<Quantity To, Dimension D, Unit U, Scalar Rep> template<Quantity To, Unit U, Scalar Rep>
requires std::Same<typename To::dimension, D> requires std::Same<typename To::dimension, typename U::dimension>
constexpr To quantity_cast(const quantity<D, U, Rep>& q) constexpr To quantity_cast(const quantity<U, Rep>& q)
{ {
using c_ratio = ratio_divide<typename U::ratio, typename To::unit::ratio>; 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>; using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
@@ -143,15 +143,14 @@ namespace units {
// quantity // quantity
template<Dimension D, Unit U, Scalar Rep> template<Unit U, Scalar Rep = double>
requires std::Same<D, typename U::dimension>
class quantity { class quantity {
Rep value_; Rep value_;
public: public:
using dimension = D;
using unit = U; using unit = U;
using rep = Rep; using rep = Rep;
using dimension = U::dimension;
static_assert(!Quantity<Rep>, "rep cannot be a quantity"); static_assert(!Quantity<Rep>, "rep cannot be a quantity");
@@ -238,163 +237,173 @@ namespace units {
}; };
// clang-format off // clang-format off
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Quantity operator+(const quantity<D, U1, Rep1>& lhs, [[nodiscard]] constexpr Quantity operator+(const quantity<U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs) const quantity<U2, Rep2>& rhs)
requires std::Same<typename U1::dimension, typename U2::dimension>
{ {
using common_rep = decltype(lhs.count() + rhs.count()); 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()); return ret(ret(lhs).count() + ret(rhs).count());
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Quantity operator-(const quantity<D, U1, Rep1>& lhs, [[nodiscard]] constexpr Quantity operator-(const quantity<U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs) const quantity<U2, Rep2>& rhs)
requires std::Same<typename U1::dimension, typename U2::dimension>
{ {
using common_rep = decltype(lhs.count() - rhs.count()); 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()); return ret(ret(lhs).count() - ret(rhs).count());
} }
// template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2> // template<Unit U, Scalar Rep1, Scalar Rep2>
template<typename D, typename U, typename Rep1, typename Rep2> template<typename U, typename Rep1, typename Rep2>
[[nodiscard]] constexpr Quantity operator*(const quantity<D, U, Rep1>& q, [[nodiscard]] constexpr Quantity operator*(const quantity<U, Rep1>& q,
const Rep2& v) const Rep2& v)
requires (!Quantity<Rep2>) requires (!Quantity<Rep2>)
{ {
using common_rep = decltype(q.count()* 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); return ret(ret(q).count() * v);
} }
//template<Scalar Rep1, Dimension D, Unit U, Scalar Rep2> //template<Scalar Rep1, Unit U, Scalar Rep2>
template<typename Rep1, typename D, typename U, typename Rep2> template<typename Rep1, typename U, typename Rep2>
[[nodiscard]] constexpr Quantity operator*(const Rep1& v, [[nodiscard]] constexpr Quantity operator*(const Rep1& v,
const quantity<D, U, Rep2>& q) const quantity<U, Rep2>& q)
requires (!Quantity<Rep1>) requires (!Quantity<Rep1>)
{ {
return q * v; return q * v;
} }
template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Quantity operator*(const quantity<D1, U1, Rep1>& lhs, [[nodiscard]] constexpr Quantity operator*(const quantity<U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs) const quantity<U2, Rep2>& rhs)
requires treat_as_floating_point<decltype(lhs.count() * rhs.count())> || requires treat_as_floating_point<decltype(lhs.count() * rhs.count())> ||
(std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1) (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 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()); return ret(lhs.count() * rhs.count());
} }
// template<Scalar Rep1, Dimension D, Unit U, Scalar Rep2> // template<Scalar Rep1, Unit U, Scalar Rep2>
template<typename Rep1, typename D, typename U, typename Rep2> template<typename Rep1, typename U, typename Rep2>
[[nodiscard]] constexpr Quantity operator/(const Rep1& v, [[nodiscard]] constexpr Quantity operator/(const Rep1& v,
const quantity<D, U, Rep2>& q) const quantity<U, Rep2>& q)
requires (!Quantity<Rep1>) requires (!Quantity<Rep1>)
{ {
Expects(q != std::remove_cvref_t<decltype(q)>(0)); 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 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 ret = quantity<downcasting_traits_t<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
using den = quantity<D, U, common_rep>; using den = quantity<U, common_rep>;
return ret(v / den(q).count()); return ret(v / den(q).count());
} }
// template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2> // template<Unit U, Scalar Rep1, Scalar Rep2>
template<typename D, typename U, typename Rep1, typename Rep2> template<typename U, typename Rep1, typename Rep2>
[[nodiscard]] constexpr Quantity operator/(const quantity<D, U, Rep1>& q, [[nodiscard]] constexpr Quantity operator/(const quantity<U, Rep1>& q,
const Rep2& v) const Rep2& v)
requires (!Quantity<Rep2>) requires (!Quantity<Rep2>)
{ {
Expects(v != Rep2{0}); Expects(v != Rep2{0});
using common_rep = decltype(q.count() / 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); return ret(ret(q).count() / v);
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs, [[nodiscard]] constexpr Scalar operator/(const quantity<U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs) const quantity<U2, Rep2>& rhs)
requires std::Same<typename U1::dimension, typename U2::dimension>
{ {
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0)); Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
using common_rep = decltype(lhs.count() / rhs.count()); 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(); return cq(lhs).count() / cq(rhs).count();
} }
template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Quantity operator/(const quantity<D1, U1, Rep1>& lhs, [[nodiscard]] constexpr Quantity operator/(const quantity<U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs) const quantity<U2, Rep2>& rhs)
requires treat_as_floating_point<decltype(lhs.count() / rhs.count())> || requires (!std::Same<typename U1::dimension, typename U2::dimension>) &&
(ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1) (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)); Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
using common_rep = decltype(lhs.count() / rhs.count()); using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide_t<D1, D2>; using dim = dimension_divide_t<typename U1::dimension, typename U2::dimension>;
using ret = quantity<dim, downcasting_traits_t<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>; using ret = quantity<downcasting_traits_t<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
return ret(lhs.count() / rhs.count()); return ret(lhs.count() / rhs.count());
} }
template<Dimension D, Unit U, Scalar Rep1, Scalar Rep2> template<Unit U, Scalar Rep1, Scalar Rep2>
[[nodiscard]] constexpr Quantity operator%(const quantity<D, U, Rep1>& q, [[nodiscard]] constexpr Quantity operator%(const quantity<U, Rep1>& q,
const Rep2& v) const Rep2& v)
{ {
using common_rep = decltype(q.count() % 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); return ret(ret(q).count() % v);
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Quantity operator%(const quantity<D, U1, Rep1>& lhs, [[nodiscard]] constexpr Quantity operator%(const quantity<U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs) const quantity<U2, Rep2>& rhs)
{ {
using common_rep = decltype(lhs.count() % rhs.count()); 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()); return ret(ret(lhs).count() % ret(rhs).count());
} }
// clang-format on // clang-format on
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[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(); return ct(lhs).count() == ct(rhs).count();
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr bool operator!=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[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); return !(lhs == rhs);
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr bool operator<(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[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(); return ct(lhs).count() < ct(rhs).count();
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr bool operator<=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[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); return !(rhs < lhs);
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr bool operator>(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[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; return rhs < lhs;
} }
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> template<Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr bool operator>=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[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); return !(lhs < rhs);
} }

View File

@@ -33,17 +33,14 @@ namespace units {
template<typename T> template<typename T>
concept bool Substance = Quantity<T> && std::Same<typename T::dimension, dimension_substance>; 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> {}; struct mole : unit<dimension_substance> {};
template<> struct downcasting_traits<downcast_from<mole>> : downcast_to<mole> {}; template<> struct downcasting_traits<downcast_from<mole>> : downcast_to<mole> {};
inline namespace literals { inline namespace literals {
// mol // mol
constexpr auto operator""_mol(unsigned long long l) { return substance<mole, std::int64_t>(l); } constexpr auto operator""_mol(unsigned long long l) { return quantity<mole, std::int64_t>(l); }
constexpr auto operator""_mol(long double l) { return substance<mole, long double>(l); } constexpr auto operator""_mol(long double l) { return quantity<mole, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -33,17 +33,14 @@ namespace units {
template<typename T> template<typename T>
concept bool ThermodynamicTemperature = Quantity<T> && std::Same<typename T::dimension, dimension_temperature>; 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> {}; struct kelvin : unit<dimension_temperature> {};
template<> struct downcasting_traits<downcast_from<kelvin>> : downcast_to<kelvin> {}; template<> struct downcasting_traits<downcast_from<kelvin>> : downcast_to<kelvin> {};
inline namespace literals { inline namespace literals {
// K // K
constexpr auto operator""_K(unsigned long long l) { return temperature<kelvin, std::int64_t>(l); } constexpr auto operator""_K(unsigned long long l) { return quantity<kelvin, std::int64_t>(l); }
constexpr auto operator""_K(long double l) { return temperature<kelvin, long double>(l); } constexpr auto operator""_K(long double l) { return quantity<kelvin, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -33,9 +33,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Time = Quantity<T> && std::Same<typename T::dimension, dimension_time>; 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> {}; struct second : unit<dimension_time> {};
template<> struct downcasting_traits<downcast_from<second>> : downcast_to<second> {}; template<> struct downcasting_traits<downcast_from<second>> : downcast_to<second> {};
@@ -57,28 +54,28 @@ namespace units {
inline namespace literals { inline namespace literals {
// ns // ns
constexpr auto operator""_ns(unsigned long long l) { return time<nanosecond, std::int64_t>(l); } constexpr auto operator""_ns(unsigned long long l) { return quantity<nanosecond, std::int64_t>(l); }
constexpr auto operator""_ns(long double l) { return time<nanosecond, long double>(l); } constexpr auto operator""_ns(long double l) { return quantity<nanosecond, long double>(l); }
// us // us
constexpr auto operator""_us(unsigned long long l) { return time<microsecond, std::int64_t>(l); } constexpr auto operator""_us(unsigned long long l) { return quantity<microsecond, std::int64_t>(l); }
constexpr auto operator""_us(long double l) { return time<microsecond, long double>(l); } constexpr auto operator""_us(long double l) { return quantity<microsecond, long double>(l); }
// ms // ms
constexpr auto operator""_ms(unsigned long long l) { return time<millisecond, std::int64_t>(l); } constexpr auto operator""_ms(unsigned long long l) { return quantity<millisecond, std::int64_t>(l); }
constexpr auto operator""_ms(long double l) { return time<millisecond, long double>(l); } constexpr auto operator""_ms(long double l) { return quantity<millisecond, long double>(l); }
// s // s
constexpr auto operator""_s(unsigned long long l) { return time<second, std::int64_t>(l); } constexpr auto operator""_s(unsigned long long l) { return quantity<second, std::int64_t>(l); }
constexpr auto operator""_s(long double l) { return time<second, long double>(l); } constexpr auto operator""_s(long double l) { return quantity<second, long double>(l); }
// min // min
constexpr auto operator""_min(unsigned long long l) { return time<minute, std::int64_t>(l); } constexpr auto operator""_min(unsigned long long l) { return quantity<minute, std::int64_t>(l); }
constexpr auto operator""_min(long double l) { return time<minute, long double>(l); } constexpr auto operator""_min(long double l) { return quantity<minute, long double>(l); }
// h // h
constexpr auto operator""_h(unsigned long long l) { return time<hour, std::int64_t>(l); } constexpr auto operator""_h(unsigned long long l) { return quantity<hour, std::int64_t>(l); }
constexpr auto operator""_h(long double l) { return time<hour, long double>(l); } constexpr auto operator""_h(long double l) { return quantity<hour, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -33,9 +33,6 @@ namespace units {
template<typename T> template<typename T>
concept bool Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>; 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> {}; struct meter_per_second : derived_unit<dimension_velocity, meter, second> {};
template<> struct downcasting_traits<downcast_from<meter_per_second>> : downcast_to<meter_per_second> {}; template<> struct downcasting_traits<downcast_from<meter_per_second>> : downcast_to<meter_per_second> {};
@@ -48,16 +45,16 @@ namespace units {
inline namespace literals { inline namespace literals {
// mps // mps
constexpr auto operator""_mps(unsigned long long l) { return velocity<meter_per_second, std::int64_t>(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 velocity<meter_per_second, long double>(l); } constexpr auto operator""_mps(long double l) { return quantity<meter_per_second, long double>(l); }
// kmph // kmph
constexpr auto operator""_kmph(unsigned long long l) { return velocity<kilometer_per_hour, std::int64_t>(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 velocity<kilometer_per_hour, long double>(l); } constexpr auto operator""_kmph(long double l) { return quantity<kilometer_per_hour, long double>(l); }
// mph // mph
constexpr auto operator""_mph(unsigned long long l) { return velocity<mile_per_hour, std::int64_t>(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 velocity<mile_per_hour, long double>(l); } constexpr auto operator""_mph(long double l) { return quantity<mile_per_hour, long double>(l); }
} // namespace literals } // namespace literals

View File

@@ -77,76 +77,76 @@ namespace {
// class invariants // class invariants
// constexpr quantity<dimension_length, second, int> q; // should a static_assert // 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<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 // constexpr quantity<dimension_length, unit<dimension_length, std::ratio<-1, 1>>, int> error(0); // should trigger a static_assert
// member types // member types
static_assert(std::is_same_v<length<meter, int>::rep, int>); static_assert(std::is_same_v<quantity<meter, int>::rep, int>);
static_assert(std::is_same_v<length<meter, double>::rep, double>); static_assert(std::is_same_v<quantity<meter, double>::rep, double>);
static_assert(std::is_same_v<length<meter, int>::unit, meter>); static_assert(std::is_same_v<quantity<meter, int>::unit, meter>);
static_assert(std::is_same_v<length<kilometer, int>::unit, kilometer>); static_assert(std::is_same_v<quantity<kilometer, int>::unit, kilometer>);
// constructors // constructors
static_assert(length<meter, int>().count() == 0); static_assert(quantity<meter, int>().count() == 0);
constexpr length<meter, int> km{1000}; constexpr quantity<meter, int> km{1000};
static_assert(km.count() == 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(quantity<meter, int>(1).count() == 1);
static_assert(length<meter, int>(my_value(1)).count() == 1); static_assert(quantity<meter, int>(my_value(1)).count() == 1);
static_assert(length<meter, my_value<int>>(1).count() == 1); static_assert(quantity<meter, my_value<int>>(1).count() == 1);
// static_assert(length<meter, int>(1.0).count() == 1); // should not compile // static_assert(quantity<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(quantity<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(quantity<meter, my_value>(1.0).count() == 1); // should not compile
static_assert(length<meter, double>(1.0).count() == 1.0); static_assert(quantity<meter, double>(1.0).count() == 1.0);
static_assert(length<meter, double>(my_value(1.0)).count() == 1.0); static_assert(quantity<meter, double>(my_value(1.0)).count() == 1.0);
static_assert(length<meter, double>(1).count() == 1.0); static_assert(quantity<meter, double>(1).count() == 1.0);
static_assert(length<meter, double>(my_value(1)).count() == 1.0); static_assert(quantity<meter, double>(my_value(1)).count() == 1.0);
static_assert(length<meter, double>(3.14).count() == 3.14); static_assert(quantity<meter, double>(3.14).count() == 3.14);
static_assert(length<meter, my_value<double>>(1.0).count() == 1.0); static_assert(quantity<meter, my_value<double>>(1.0).count() == 1.0);
static_assert(length<meter, my_value<double>>(1).count() == 1.0); static_assert(quantity<meter, my_value<double>>(1).count() == 1.0);
static_assert(length<meter, my_value<double>>(3.14).count() == 3.14); static_assert(quantity<meter, my_value<double>>(3.14).count() == 3.14);
static_assert(length<meter, int>(km).count() == 1000); static_assert(quantity<meter, int>(km).count() == 1000);
// static_assert(length<meter, int>(length<meter, double>(3.14)).count() == 3); // should not compile // static_assert(quantity<meter, int>(quantity<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(quantity<meter, int>(quantity_cast<quantity<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(quantity<meter, int>(quantity<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(quantity<meter, my_value>(1000.0_m).count() == 1000); // should not compile
static_assert(length<meter, double>(1000.0_m).count() == 1000.0); static_assert(quantity<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(quantity<meter, double>(quantity<meter, my_value<double>>(1000.0)).count() == 1000.0);
static_assert(length<meter, my_value<double>>(1000.0_m).count() == 1000.0); static_assert(quantity<meter, my_value<double>>(1000.0_m).count() == 1000.0);
static_assert(length<meter, double>(km).count() == 1000.0); static_assert(quantity<meter, double>(km).count() == 1000.0);
static_assert(length<meter, my_value<double>>(km).count() == 1000.0); static_assert(quantity<meter, my_value<double>>(km).count() == 1000.0);
static_assert(length<meter, int>(1_km).count() == 1000); static_assert(quantity<meter, int>(1_km).count() == 1000);
// static_assert(length<meter, int>(1_s).count() == 1); // should not compile // static_assert(quantity<meter, int>(1_s).count() == 1); // should not compile
// static_assert(length<kilometer, int>(1010_m).count() == 1); // should not compile // static_assert(quantity<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<kilometer, int>(quantity_cast<quantity<kilometer, my_value<int>>>(1010_m)).count() == 1);
// assignment operator // assignment operator
static_assert([]() { static_assert([]() {
length<meter, int> l1(1), l2(2); quantity<meter, int> l1(1), l2(2);
return l2 = l1; return l2 = l1;
}() }()
.count() == 1); .count() == 1);
// static member functions // static member functions
static_assert(length<meter, int>::zero().count() == 0); static_assert(quantity<meter, int>::zero().count() == 0);
static_assert(length<meter, int>::min().count() == std::numeric_limits<int>::lowest()); static_assert(quantity<meter, int>::min().count() == std::numeric_limits<int>::lowest());
static_assert(length<meter, int>::max().count() == std::numeric_limits<int>::max()); static_assert(quantity<meter, int>::max().count() == std::numeric_limits<int>::max());
static_assert(length<meter, double>::zero().count() == 0.0); static_assert(quantity<meter, double>::zero().count() == 0.0);
static_assert(length<meter, double>::min().count() == std::numeric_limits<double>::lowest()); static_assert(quantity<meter, double>::min().count() == std::numeric_limits<double>::lowest());
static_assert(length<meter, double>::max().count() == std::numeric_limits<double>::max()); static_assert(quantity<meter, double>::max().count() == std::numeric_limits<double>::max());
static_assert(length<meter, my_value<int>>::zero().count() == 0); static_assert(quantity<meter, my_value<int>>::zero().count() == 0);
static_assert(length<meter, my_value<int>>::min().count() == std::numeric_limits<int>::lowest()); static_assert(quantity<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(quantity<meter, my_value<int>>::max().count() == std::numeric_limits<int>::max());
static_assert(length<meter, my_value<double>>::zero().count() == 0.0); static_assert(quantity<meter, my_value<double>>::zero().count() == 0.0);
static_assert(length<meter, my_value<double>>::min().count() == std::numeric_limits<double>::lowest()); static_assert(quantity<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, my_value<double>>::max().count() == std::numeric_limits<double>::max());
// unary member operators // unary member operators
@@ -160,19 +160,19 @@ namespace {
static_assert([](auto v) { static_assert([](auto v) {
auto vv = v++; auto vv = v++;
return std::make_pair(v, vv); 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) { static_assert([](auto v) {
auto vv = ++v; auto vv = ++v;
return std::make_pair(v, vv); 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) { static_assert([](auto v) {
auto vv = v--; auto vv = v--;
return std::make_pair(v, vv); 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) { static_assert([](auto v) {
auto vv = --v; auto vv = --v;
return std::make_pair(v, vv); 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 // compound assignment
@@ -185,21 +185,21 @@ namespace {
// non-member arithmetic operators // 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(quantity<meter, int>() + quantity<meter, double>()), quantity<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(quantity<meter, int>() + quantity<meter, double>()), quantity<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(quantity<kilometer, int>() + quantity<meter, double>()), quantity<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(quantity<meter, double>() - quantity<meter, int>()), quantity<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(quantity<kilometer, double>() - quantity<meter, int>()), quantity<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(quantity<meter, int>() * 1.0), quantity<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(1.0 * quantity<meter, int>()), quantity<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(quantity<meter_per_second, int>() * units::quantity<second, int>()), quantity<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(1 / units::quantity<second, int>()), quantity<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(quantity<meter, int>() / 1.0), quantity<meter, double>>);
static_assert(std::is_same_v<decltype(length<meter, int>() / length<meter, double>()), double>); static_assert(std::is_same_v<decltype(quantity<meter, int>() / quantity<meter, double>()), double>);
static_assert(std::is_same_v<decltype(length<kilometer, int>() / length<meter, double>()), double>); static_assert(std::is_same_v<decltype(quantity<kilometer, int>() / quantity<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(quantity<meter, int>() / units::quantity<second, int>()), quantity<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(quantity<meter, int>() % short(1)), quantity<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, short>(1)), quantity<meter, int>>);
static_assert((1_m + km).count() == 1001); static_assert((1_m + km).count() == 1001);
static_assert((1_m + 1_km).count() == 1001); static_assert((1_m + 1_km).count() == 1001);
@@ -247,19 +247,19 @@ namespace {
// is_quantity // is_quantity
static_assert(Quantity<length<millimeter, int>>); static_assert(Quantity<quantity<millimeter, int>>);
// common_quantity // 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<quantity<meter, int>, quantity<kilometer, int>>, quantity<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<quantity<kilometer, long long>, quantity<meter, int>>, quantity<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<kilometer, long long>, quantity<millimeter, double>>, quantity<millimeter, double>>);
// quantity_cast // quantity_cast
// static_assert(quantity_cast<int>(2_km).count() == 2000); // should not compile // 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<quantity<meter, int>>(2_km).count() == 2000);
static_assert(quantity_cast<length<kilometer, int>>(2000_m).count() == 2); static_assert(quantity_cast<quantity<kilometer, int>>(2000_m).count() == 2);
// time // time

View File

@@ -74,7 +74,7 @@ namespace {
// velocity // 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_m / 5_s == 2_mps);
static_assert(10 / 5_s * 1_m == 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(2_km / 2_kmph == 1_h);
// static_assert(2000_m / 2_kmph == 1_h); // should not compile // 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 // area