feat!: 💥 dimensionless quantities refactored

Dimensionless quantities are now represented by quantity types rather
than by plain representation types. Only dimensionless quantities with
`unitless` unit are implicitly convertible from representation types.

`units::exp()` now is a function doing std::exp() on a representation
type (previous `units::exp` class template was renamed to
`units::exponent`).

BREAKING_CHANGE: gcc-9.3 support removed
BREAKING_CHANGE: `exp` and `Exp` renamed to `exponent` and `Exponent`
Resolves #27
Resolves #42
This commit is contained in:
Mateusz Pusz
2020-09-08 11:02:16 +02:00
parent c8b60b80c1
commit 563b358d5e
47 changed files with 599 additions and 422 deletions

View File

@@ -15,6 +15,8 @@
- FPS system added (thanks [@mikeford3](https://github.com/mikeford3)) - FPS system added (thanks [@mikeford3](https://github.com/mikeford3))
- `quantity_point` support added (thanks [@johelegp](https://github.com/johelegp)) - `quantity_point` support added (thanks [@johelegp](https://github.com/johelegp))
- `ratio` changed to the NTTP kind - `ratio` changed to the NTTP kind
- `exp` and `Exp` renamed to `exponent` and `Exponent`
- Added support for `exp()` mathematical support
- **0.5.0 May 17, 2020** - **0.5.0 May 17, 2020**
- Major refactoring and rewrite of the library - Major refactoring and rewrite of the library

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -14,18 +14,18 @@ The same can be observed during debugging of a source code that use template ali
Let's assume that we want to provide a user friendly name for a derived dimension of capacitance Let's assume that we want to provide a user friendly name for a derived dimension of capacitance
quantity. Other libraries will do it in the following way:: quantity. Other libraries will do it in the following way::
using dim_capacitance = detail::derived_dimension_base<exp<si::dim_electric_current, 2>, using dim_capacitance = detail::derived_dimension_base<exponent<si::dim_electric_current, 2>,
exp<si::dim_length, -2>, exponent<si::dim_length, -2>,
exp<si::dim_mass, -1>, exponent<si::dim_mass, -1>,
exp<si::dim_time, 4>>; exponent<si::dim_time, 4>>;
The above solution does provide a good developer's experience but a really poor one for the end The above solution does provide a good developer's experience but a really poor one for the end
user. If we will get a compilation error message containing `dim_capacitance` in most cases user. If we will get a compilation error message containing `dim_capacitance` in most cases
the compiler will print the following type instead of the alias:: the compiler will print the following type instead of the alias::
units::detail::derived_dimension_base<units::exp<units::physical::si::dim_electric_current, 2, 1>, units::detail::derived_dimension_base<units::exponent<units::physical::si::dim_electric_current, 2, 1>,
units::exp<units::physical::si::dim_length, -2, 1>, units::exp<units::physical::si::dim_mass, -1, 1>, units::exponent<units::physical::si::dim_length, -2, 1>, units::exponent<units::physical::si::dim_mass,
units::exp<units::physical::si::dim_time, 4, 1> > -1, 1>, units::exponent<units::physical::si::dim_time, 4, 1> >
You can notice that in case of **mp-units** even this long syntax was carefully selected to You can notice that in case of **mp-units** even this long syntax was carefully selected to
provide quite good user experience (some other units libraries produce a type that cannot easily provide quite good user experience (some other units libraries produce a type that cannot easily
@@ -48,7 +48,7 @@ to use inheritance:
.. ..
http://www.nomnoml.com http://www.nomnoml.com
[derived_dimension_base<exp<si::dim_length, 2>>]<:-[dim_area] [derived_dimension_base<exponent<si::dim_length, 2>>]<:-[dim_area]
This gives us a nice looking strong type when directly used by the user. However, we just got This gives us a nice looking strong type when directly used by the user. However, we just got
ourselves into problems. The library's framework does not know how to switch from a long ourselves into problems. The library's framework does not know how to switch from a long
@@ -79,9 +79,9 @@ The downcasting facility is provided by injecting two classes into our hierarchy
.. ..
http://www.nomnoml.com http://www.nomnoml.com
[downcast_base<detail::derived_dimension_base<exp<si::dim_length, 2>>>]<:-[detail::derived_dimension_base<exp<si::dim_length, 2>>] [downcast_base<detail::derived_dimension_base<exponent<si::dim_length, 2>>>]<:-[detail::derived_dimension_base<exponent<si::dim_length, 2>>]
[detail::derived_dimension_base<exp<si::dim_length, 2>>]<:-[downcast_child<dim_area, detail::derived_dimension_base<exp<si::dim_length, 2>>>] [detail::derived_dimension_base<exponent<si::dim_length, 2>>]<:-[downcast_child<dim_area, detail::derived_dimension_base<exponent<si::dim_length, 2>>>]
[downcast_child<dim_area, detail::derived_dimension_base<exp<si::dim_length, 2>>>]<:-[dim_area] [downcast_child<dim_area, detail::derived_dimension_base<exponent<si::dim_length, 2>>>]<:-[dim_area]
In the above example: In the above example:

View File

@@ -97,14 +97,6 @@ Unfortunately, if `using-directives <https://en.cppreference.com/w/cpp/language/
collide with C `time <https://en.cppreference.com/w/c/chrono/time>`_ function. In such a case the library's collide with C `time <https://en.cppreference.com/w/c/chrono/time>`_ function. In such a case the library's
`time` function needs to be prefixed with at least one (or all) namespace names. `time` function needs to be prefixed with at least one (or all) namespace names.
error: template argument 1 is invalid
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Again, usage of ``using namespace units``
`using-directive <https://en.cppreference.com/w/cpp/language/namespace#Using-directives>`_ may result in
the collision between `units::exp` class template and C `exp <https://en.cppreference.com/w/c/numeric/math/exp>`_
function. In such a case the library's `exp` class template needs to be prefixed with `units` namespace name.

View File

@@ -13,9 +13,9 @@ The most important concepts in the library are `Unit`, `Dimension`,
http://www.nomnoml.com http://www.nomnoml.com
[<abstract>Dimension| [<abstract>Dimension|
[base_dimension<Symbol, Unit>]<-[exp<Dimension, Num, Den>] [base_dimension<Symbol, Unit>]<-[exponent<Dimension, Num, Den>]
[derived_dimension<Child, Unit, Exponent...>]<-[exp<Dimension, Num, Den>] [derived_dimension<Child, Unit, Exponent...>]<-[exponent<Dimension, Num, Den>]
[exp<Dimension, Num, Den>]<-[derived_dimension<Child, Unit, Exponent...>] [exponent<Dimension, Num, Den>]<-[derived_dimension<Child, Unit, Exponent...>]
] ]
[<abstract>Quantity| [<abstract>Quantity|

View File

@@ -147,9 +147,9 @@ The above dimensions can be defined in the library with the
namespace si { namespace si {
struct dim_area : derived_dimension<dim_area, square_metre, struct dim_area : derived_dimension<dim_area, square_metre,
exp<dim_length, 2>> {}; exponent<dim_length, 2>> {};
struct dim_speed : derived_dimension<dim_speed, metre_per_second, struct dim_speed : derived_dimension<dim_speed, metre_per_second,
exp<dim_length, 1>, exp<dim_time, -1>> {}; exponent<dim_length, 1>, exponent<dim_time, -1>> {};
} }
@@ -179,9 +179,9 @@ matter. Even if we define the above as:
namespace si { namespace si {
struct dim_area : derived_dimension<dim_area, square_metre, struct dim_area : derived_dimension<dim_area, square_metre,
exp<dim_length, 1>, exp<dim_length, 1>> {}; exponent<dim_length, 1>, exponent<dim_length, 1>> {};
struct dim_speed : derived_dimension<dim_speed, metre_per_second, struct dim_speed : derived_dimension<dim_speed, metre_per_second,
exp<dim_time, -1>, exp<dim_length, 1>> {}; exponent<dim_time, -1>, exponent<dim_length, 1>> {};
} }

View File

@@ -120,17 +120,17 @@ will result in a different unnamed unit symbol:
:emphasize-lines: 2-4, 6-8, 10-12 :emphasize-lines: 2-4, 6-8, 10-12
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second, struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_mass, 1>, exponent<si::dim_mass, 1>,
exp<si::dim_length, 1>, exponent<si::dim_length, 1>,
exp<si::dim_time, -1>> {}; // kg ⋅ m/s exponent<si::dim_time, -1>> {}; // kg ⋅ m/s
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second, struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_length, 1>, exponent<si::dim_length, 1>,
exp<si::dim_mass, 1>, exponent<si::dim_mass, 1>,
exp<si::dim_time, -1>> {}; // m ⋅ kg/s exponent<si::dim_time, -1>> {}; // m ⋅ kg/s
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second, struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_time, -1>, exponent<si::dim_time, -1>,
exp<si::dim_length, 1>, exponent<si::dim_length, 1>,
exp<si::dim_mass, 1>> {}; // 1/s ⋅ m ⋅ kg exponent<si::dim_mass, 1>> {}; // 1/s ⋅ m ⋅ kg
where ``kilogram_metre_per_second`` is defined as:: where ``kilogram_metre_per_second`` is defined as::
@@ -143,8 +143,8 @@ However, the easiest way to define momentum is just to use the
:emphasize-lines: 3 :emphasize-lines: 3
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second, struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_mass, 1>, exponent<si::dim_mass, 1>,
exp<si::dim_speed, 1>> {}; // kg ⋅ m/s exponent<si::dim_speed, 1>> {}; // kg ⋅ m/s
In such a case the library will do its magic and will automatically In such a case the library will do its magic and will automatically
unpack a provided derived dimension to its base dimensions in order to unpack a provided derived dimension to its base dimensions in order to
@@ -161,8 +161,8 @@ of ``N/m``):
:emphasize-lines: 2 :emphasize-lines: 2
struct dim_surface_tension : derived_dimension<dim_surface_tension, newton_per_metre, struct dim_surface_tension : derived_dimension<dim_surface_tension, newton_per_metre,
exp<si::dim_force, 1>, exponent<si::dim_force, 1>,
exp<si::dim_length, -1>> {}; // N/m exponent<si::dim_length, -1>> {}; // N/m
If we defined the above in terms of base units we would end up with If we defined the above in terms of base units we would end up with
a ``kg/s²`` derived unit symbol. a ``kg/s²`` derived unit symbol.
@@ -194,7 +194,7 @@ where `no_prefix` is a special tag type describing that the library should
not allow to define a new prefixed unit that would use this unit as a not allow to define a new prefixed unit that would use this unit as a
reference ("kilohours" does not have much sense, right?). The `ratio` type reference ("kilohours" does not have much sense, right?). The `ratio` type
used in the definition is really similar to ``std::ratio`` but it takes used in the definition is really similar to ``std::ratio`` but it takes
an additional ``Exp`` template parameter that defines the exponent of the ratio. an additional ``Exponent`` template parameter that defines the exponent of the ratio.
Another important difference is the fact that the objects of that class are used Another important difference is the fact that the objects of that class are used
as class NTTPs rather then a type template parameter kind. as class NTTPs rather then a type template parameter kind.

View File

@@ -27,7 +27,7 @@ Concepts
.. concept:: template<typename T> Exponent .. concept:: template<typename T> Exponent
A concept matching dimension's exponents. Satisfied by all instantiations of :class:`exp`. A concept matching dimension's exponents. Satisfied by all instantiations of :class:`exponent`.
.. concept:: template<typename T> DerivedDimension .. concept:: template<typename T> DerivedDimension

View File

@@ -4,7 +4,7 @@ Dimensions
.. doxygenstruct:: units::base_dimension .. doxygenstruct:: units::base_dimension
:members: :members:
.. doxygenstruct:: units::exp .. doxygenstruct:: units::exponent
:members: :members:
.. doxygenstruct:: units::derived_dimension .. doxygenstruct:: units::derived_dimension

View File

@@ -115,7 +115,7 @@ coherent unit::
// new derived dimensions // new derived dimensions
struct dim_desk_rate : derived_dimension<dim_desk_rate, square_metre_per_second, struct dim_desk_rate : derived_dimension<dim_desk_rate, square_metre_per_second,
exp<si::dim_area, 1>, exp<si::dim_time, -1>> {}; exponent<si::dim_area, 1>, exponent<si::dim_time, -1>> {};
// our unit of interest for a new derived dimension // our unit of interest for a new derived dimension
struct desk_per_hour : deduced_unit<desk_per_hour, dim_desk_rate, desk, si::hour> {}; struct desk_per_hour : deduced_unit<desk_per_hour, dim_desk_rate, desk, si::hour> {};
@@ -164,7 +164,8 @@ With the above we can now define a new derived dimension::
struct person_per_square_metre : unit<person_per_square_metre> {}; struct person_per_square_metre : unit<person_per_square_metre> {};
struct dim_occupancy_rate : derived_dimension<dim_occupancy_rate, person_per_square_metre, struct dim_occupancy_rate : derived_dimension<dim_occupancy_rate, person_per_square_metre,
exp<dim_people, 1>, exp<si::dim_area, -1>> {}; exponent<dim_people, 1>,
exponent<si::dim_area, -1>> {};
struct person_per_desk : deduced_unit<person_per_desk, dim_occupancy_rate, person, desk> {}; struct person_per_desk : deduced_unit<person_per_desk, dim_occupancy_rate, person, desk> {};

View File

@@ -46,7 +46,7 @@ we forget to include a header file with the resulting dimension definition:
constexpr auto result = 144q_km / 2q_h; constexpr auto result = 144q_km / 2q_h;
static_assert(is_same_v<decltype(result)::dimension, static_assert(is_same_v<decltype(result)::dimension,
unknown_dimension<exp<dim_length, 1>, exp<dim_time, -1>>>); unknown_dimension<exponent<dim_length, 1>, exponent<dim_time, -1>>>);
static_assert(is_same_v<decltype(result)::unit, static_assert(is_same_v<decltype(result)::unit,
scaled_unit<ratio(1, 36, 1), unknown_coherent_unit>>); scaled_unit<ratio(1, 36, 1), unknown_coherent_unit>>);

View File

@@ -33,7 +33,6 @@ add_example(clcpp_response)
add_example(conversion_factor) add_example(conversion_factor)
add_example(experimental_angle) add_example(experimental_angle)
add_example(foot_pound_second) add_example(foot_pound_second)
add_example(glide_computer)
add_example(kalman_filter-alpha_beta_filter_example2) add_example(kalman_filter-alpha_beta_filter_example2)
conan_check_testing(linear_algebra) conan_check_testing(linear_algebra)
@@ -51,6 +50,7 @@ if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# TODO Those examples use Concepts terse syntax not yet supported by MSVC # TODO Those examples use Concepts terse syntax not yet supported by MSVC
add_example(avg_speed) add_example(avg_speed)
add_example(glide_computer)
add_example(hello_units) add_example(hello_units)
add_example(total_energy) add_example(total_energy)

View File

@@ -23,8 +23,8 @@
#include <units/physical/si/capacitance.h> #include <units/physical/si/capacitance.h>
#include <units/physical/si/resistance.h> #include <units/physical/si/resistance.h>
#include <units/physical/si/time.h> #include <units/physical/si/time.h>
#include <units/math.h>
#include "./voltage.h" #include "./voltage.h"
#include <cmath>
#include <iostream> #include <iostream>
using namespace units::experimental; using namespace units::experimental;
@@ -41,7 +41,7 @@ int main()
constexpr auto R = 4.7q_kR; constexpr auto R = 4.7q_kR;
for (auto t = 0q_ms; t <= 50q_ms; ++t) { for (auto t = 0q_ms; t <= 50q_ms; ++t) {
const auto Vt = V0 * std::exp(-t / (R * C)); const auto Vt = V0 * units::exp(-t / (R * C));
std::cout << "at " << t << " voltage is "; std::cout << "at " << t << " voltage is ";

View File

@@ -24,7 +24,7 @@
#include <units/physical/si/resistance.h> #include <units/physical/si/resistance.h>
#include <units/physical/si/time.h> #include <units/physical/si/time.h>
#include <units/physical/si/voltage.h> #include <units/physical/si/voltage.h>
#include <cmath> #include <units/math.h>
#include <iostream> #include <iostream>
int main() int main()
@@ -41,7 +41,7 @@ int main()
constexpr auto R = 4.7q_kR; constexpr auto R = 4.7q_kR;
for (auto t = 0q_ms; t <= 50q_ms; ++t) { for (auto t = 0q_ms; t <= 50q_ms; ++t) {
const Voltage AUTO Vt = V0 * std::exp(-t / (R * C)); const Voltage AUTO Vt = V0 * units::exp(-t / (R * C));
std::cout << "at " << t << " voltage is "; std::cout << "at " << t << " voltage is ";

View File

@@ -46,6 +46,7 @@ template<typename Q, direction D>
requires Quantity<Q> || QuantityPoint<Q> requires Quantity<Q> || QuantityPoint<Q>
class vector { class vector {
public: public:
using value_type = Q;
using magnitude_type = Q; using magnitude_type = Q;
static constexpr direction dir = D; static constexpr direction dir = D;
@@ -74,6 +75,43 @@ public:
return *this; return *this;
} }
template<typename Q2>
[[nodiscard]] friend constexpr auto operator+(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() + rhs.magnitude(); }
{
using ret_type = decltype(lhs.magnitude() + rhs.magnitude());
return vector<ret_type, D>(lhs.magnitude() + rhs.magnitude());
}
template<typename Q2>
[[nodiscard]] friend constexpr auto operator-(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() - rhs.magnitude(); }
{
using ret_type = decltype(lhs.magnitude() - rhs.magnitude());
return vector<ret_type, D>(lhs.magnitude() - rhs.magnitude());
}
template<typename V>
[[nodiscard]] friend constexpr auto operator*(const vector& lhs, const V& value)
requires (Scalar<V> || Dimensionless<V>) && requires { lhs.magnitude() * value; }
{
return vector<Q, D>(lhs.magnitude() * value);
}
template<typename V>
[[nodiscard]] friend constexpr auto operator*(const V& value, const vector& rhs)
requires (Scalar<V> || Dimensionless<V>) && requires { value * rhs.magnitude(); }
{
return vector<Q, D>(value * rhs.magnitude());
}
template<typename Q2, direction D2>
[[nodiscard]] friend constexpr auto operator/(const vector& lhs, const vector<Q2, D2>& rhs)
requires requires { lhs.magnitude() / rhs.magnitude(); }
{
return lhs.magnitude() / rhs.magnitude();
}
#if COMP_MSVC || COMP_GCC >= 10 #if COMP_MSVC || COMP_GCC >= 10
template<typename Q2> template<typename Q2>
@@ -149,42 +187,6 @@ private:
Q magnitude_{}; Q magnitude_{};
}; };
template<typename Q1, typename Q2, direction D>
[[nodiscard]] constexpr auto operator+(const vector<Q1, D>& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() + rhs.magnitude(); }
{
using ret_type = decltype(lhs.magnitude() + rhs.magnitude());
return vector<ret_type, D>(lhs.magnitude() + rhs.magnitude());
}
template<typename Q1, typename Q2, direction D>
[[nodiscard]] constexpr auto operator-(const vector<Q1, D>& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() - rhs.magnitude(); }
{
using ret_type = decltype(lhs.magnitude() - rhs.magnitude());
return vector<ret_type, D>(lhs.magnitude() - rhs.magnitude());
}
template<typename Q, direction D, Scalar V>
[[nodiscard]] constexpr auto operator*(const vector<Q, D>& lhs, const V& value)
requires requires { lhs.magnitude() * value; }
{
return vector<Q, D>(lhs.magnitude() * value);
}
template<typename Q, direction D, Scalar V>
[[nodiscard]] constexpr auto operator*(const V& value, const vector<Q, D>& rhs)
requires requires { value * rhs.magnitude(); }
{
return vector<Q, D>(value * rhs.magnitude());
}
template<typename Q1, typename Q2, direction D1, direction D2>
[[nodiscard]] constexpr auto operator/(const vector<Q1, D1>& lhs, const vector<Q2, D2>& rhs)
requires requires { lhs.magnitude() / rhs.magnitude(); }
{
return lhs.magnitude() / rhs.magnitude();
}
template<typename T> template<typename T>
inline constexpr bool is_vector = false; inline constexpr bool is_vector = false;
@@ -276,7 +278,7 @@ auto get_gliders()
return gliders; return gliders;
} }
constexpr double glide_ratio(const glider::polar_point& polar) constexpr Dimensionless AUTO glide_ratio(const glider::polar_point& polar)
{ {
return polar.v / -polar.climb; return polar.v / -polar.climb;
} }

View File

@@ -23,7 +23,7 @@
#pragma once #pragma once
#include <units/base_dimension.h> #include <units/base_dimension.h>
#include <units/exp.h> #include <units/exponent.h>
#include <units/ratio.h> #include <units/ratio.h>
namespace units::detail { namespace units::detail {
@@ -45,7 +45,7 @@ constexpr ratio exp_ratio()
template<typename... Es> template<typename... Es>
constexpr ratio base_units_ratio(exp_list<Es...>) constexpr ratio base_units_ratio(exp_list<Es...>)
{ {
return (exp_ratio<Es>() * ...); return (exp_ratio<Es>() * ... * ratio(1));
} }
} // namespace units::detail } // namespace units::detail

View File

@@ -77,7 +77,7 @@ constexpr auto exp_text()
} }
template<typename... Es> template<typename... Es>
inline constexpr int negative_exp_count = ((Es::num < 0 ? 1 : 0) + ...); inline constexpr int negative_exp_count = ((Es::num < 0 ? 1 : 0) + ... + 0);
template<typename... Us, typename... Es, std::size_t... Idxs> template<typename... Us, typename... Es, std::size_t... Idxs>
constexpr auto deduced_symbol_text(exp_list<Es...>, std::index_sequence<Idxs...>) constexpr auto deduced_symbol_text(exp_list<Es...>, std::index_sequence<Idxs...>)

View File

@@ -24,7 +24,7 @@
#include <units/base_dimension.h> #include <units/base_dimension.h>
#include <units/bits/external/downcasting.h> #include <units/bits/external/downcasting.h>
#include <units/exp.h> #include <units/exponent.h>
namespace units::detail { namespace units::detail {
@@ -35,19 +35,18 @@ namespace units::detail {
* quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors. * quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors.
* A power of a factor is the factor raised to an exponent. * A power of a factor is the factor raised to an exponent.
* *
* A derived dimension can be formed from multiple exponents (i.e. speed is represented as "exp<L, 1>, exp<T, -1>"). * A derived dimension can be formed from multiple exponents (i.e. speed is represented as "exponent<L, 1>, exponent<T, -1>").
* It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just * It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just
* "exp<T, -1>"). * "exponent<T, -1>").
* *
* @note This class template is used by the library engine and should not be directly instantiated by the user. * @note This class template is used by the library engine and should not be directly instantiated by the user.
* *
* @tparam E a first exponent of a derived dimension * @tparam Es zero or more exponents of a derived dimension
* @tparam ERest zero or more following exponents of a derived dimension
*/ */
template<Exponent E, Exponent... ERest> template<Exponent... Es>
requires (BaseDimension<typename E::dimension> && ... && BaseDimension<typename ERest::dimension>) requires (BaseDimension<typename Es::dimension> && ...)
struct derived_dimension_base : downcast_base<derived_dimension_base<E, ERest...>> { struct derived_dimension_base : downcast_base<derived_dimension_base<Es...>> {
using exponents = exp_list<E, ERest...>; using exponents = exp_list<Es...>;
}; };
template<typename T> template<typename T>

View File

@@ -23,7 +23,7 @@
#pragma once #pragma once
#include <units/bits/external/type_list.h> #include <units/bits/external/type_list.h>
#include <units/exp.h> #include <units/exponent.h>
#include <ratio> // TODO remove this dependency with #11 #include <ratio> // TODO remove this dependency with #11
namespace units::detail { namespace units::detail {
@@ -55,13 +55,13 @@ struct dim_consolidate<exp_list<E1, ERest...>> {
}; };
template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest> template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest>
struct dim_consolidate<exp_list<exp<Dim, Num1, Den1>, exp<Dim, Num2, Den2>, ERest...>> { struct dim_consolidate<exp_list<exponent<Dim, Num1, Den1>, exponent<Dim, Num2, Den2>, ERest...>> {
// TODO: we have ration_add now, but dim_consolidate etc, now need to cope with our new ratio // TODO: we have ration_add now, but dim_consolidate etc, now need to cope with our new ratio
using r1 = std::ratio<Num1, Den1>; using r1 = std::ratio<Num1, Den1>;
using r2 = std::ratio<Num2, Den2>; using r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>; using r = std::ratio_add<r1, r2>;
using type = conditional<r::num == 0, typename dim_consolidate<exp_list<ERest...>>::type, using type = conditional<r::num == 0, typename dim_consolidate<exp_list<ERest...>>::type,
typename dim_consolidate<exp_list<exp<Dim, r::num, r::den>, ERest...>>::type>; typename dim_consolidate<exp_list<exponent<Dim, r::num, r::den>, ERest...>>::type>;
}; };
} // namespace units::detail } // namespace units::detail

View File

@@ -24,7 +24,7 @@
#include <units/bits/derived_dimension_base.h> #include <units/bits/derived_dimension_base.h>
#include <units/bits/external/type_list.h> #include <units/bits/external/type_list.h>
#include <units/exp.h> #include <units/exponent.h>
namespace units::detail { namespace units::detail {
@@ -42,17 +42,17 @@ struct dim_unpack<> {
}; };
template<BaseDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest> template<BaseDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
struct dim_unpack<exp<Dim, Num, Den>, ERest...> { struct dim_unpack<exponent<Dim, Num, Den>, ERest...> {
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exp<Dim, Num, Den>>; using type = type_list_push_front<typename dim_unpack<ERest...>::type, exponent<Dim, Num, Den>>;
}; };
template<DerivedDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest> template<DerivedDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
struct dim_unpack<exp<Dim, Num, Den>, ERest...> { struct dim_unpack<exponent<Dim, Num, Den>, ERest...> {
using type = TYPENAME dim_unpack<exp<downcast_base_t<Dim>, Num, Den>, ERest...>::type; using type = TYPENAME dim_unpack<exponent<downcast_base_t<Dim>, Num, Den>, ERest...>::type;
}; };
template<Exponent... Es, std::intmax_t Num, std::intmax_t Den, Exponent... ERest> template<Exponent... Es, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
struct dim_unpack<exp<derived_dimension_base<Es...>, Num, Den>, ERest...> { struct dim_unpack<exponent<derived_dimension_base<Es...>, Num, Den>, ERest...> {
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exp_multiply<Es, Num, Den>...>; using type = type_list_push_front<typename dim_unpack<ERest...>::type, exp_multiply<Es, Num, Den>...>;
}; };

View File

@@ -44,7 +44,7 @@ template<Exponent E1, Exponent E2>
struct equivalent_exp : std::false_type {}; struct equivalent_exp : std::false_type {};
template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2> template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2>
struct equivalent_exp<exp<Dim1, Num, Den>, exp<Dim2, Num, Den>> : equivalent_dim_impl<Dim1, Dim2> {}; struct equivalent_exp<exponent<Dim1, Num, Den>, exponent<Dim2, Num, Den>> : equivalent_dim_impl<Dim1, Dim2> {};
template<DerivedDimension D1, DerivedDimension D2> template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_derived_dim : std::false_type {}; struct equivalent_derived_dim : std::false_type {};
@@ -68,11 +68,10 @@ inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::valu
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit` * dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit`
* and ratio(1). * and ratio(1).
* *
* @tparam E the list of exponents of ingredient dimensions * @tparam Es the list of exponents of ingredient dimensions
* @tparam ERest the list of exponents of ingredient dimensions
*/ */
template<Exponent E, Exponent... ERest> template<Exponent... Es>
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, unknown_coherent_unit, E, ERest...> {}; struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit, Es...> {};
namespace detail { namespace detail {
@@ -113,11 +112,11 @@ struct dim_invert_impl;
template<BaseDimension D> template<BaseDimension D>
struct dim_invert_impl<D> { struct dim_invert_impl<D> {
using type = downcast_dimension<derived_dimension_base<exp<D, -1>>>; using type = downcast_dimension<derived_dimension_base<exponent<D, -1>>>;
}; };
template<BaseDimension D> template<BaseDimension D>
struct dim_invert_impl<derived_dimension_base<exp<D, -1>>> { struct dim_invert_impl<derived_dimension_base<exponent<D, -1>>> {
using type = D; using type = D;
}; };
@@ -147,7 +146,7 @@ struct to_dimension<exp_list<Es...>> {
}; };
template<BaseDimension D> template<BaseDimension D>
struct to_dimension<exp_list<exp<D, 1>>> { struct to_dimension<exp_list<exponent<D, 1>>> {
using type = D; using type = D;
}; };
@@ -168,12 +167,12 @@ struct dimension_multiply_impl;
template<BaseDimension D1, BaseDimension D2> template<BaseDimension D1, BaseDimension D2>
struct dimension_multiply_impl<D1, D2> { struct dimension_multiply_impl<D1, D2> {
using type = downcast_dimension<merge_dimension<derived_dimension_base<exp<D1, 1>>, derived_dimension_base<exp<D2, 1>>>>; using type = downcast_dimension<merge_dimension<derived_dimension_base<exponent<D1, 1>>, derived_dimension_base<exponent<D2, 1>>>>;
}; };
template<BaseDimension D1, DerivedDimension D2> template<BaseDimension D1, DerivedDimension D2>
struct dimension_multiply_impl<D1, D2> { struct dimension_multiply_impl<D1, D2> {
using type = downcast_dimension<merge_dimension<derived_dimension_base<exp<D1, 1>>, typename D2::downcast_base_type>>; using type = downcast_dimension<merge_dimension<derived_dimension_base<exponent<D1, 1>>, typename D2::downcast_base_type>>;
}; };
template<DerivedDimension D1, BaseDimension D2> template<DerivedDimension D1, BaseDimension D2>
@@ -202,11 +201,11 @@ struct dimension_sqrt_impl;
template<BaseDimension D> template<BaseDimension D>
struct dimension_sqrt_impl<D> { struct dimension_sqrt_impl<D> {
using type = downcast_dimension<derived_dimension_base<exp<D, 1, 2>>>; using type = downcast_dimension<derived_dimension_base<exponent<D, 1, 2>>>;
}; };
template<BaseDimension D> template<BaseDimension D>
struct dimension_sqrt_impl<derived_dimension_base<exp<D, 2>>> { struct dimension_sqrt_impl<derived_dimension_base<exponent<D, 2>>> {
using type = D; using type = D;
}; };
@@ -233,7 +232,7 @@ struct dimension_pow_impl;
template<BaseDimension D, std::intmax_t N> template<BaseDimension D, std::intmax_t N>
struct dimension_pow_impl<D, N> { struct dimension_pow_impl<D, N> {
using type = downcast_dimension<derived_dimension_base<exp<D, N>>>; using type = downcast_dimension<derived_dimension_base<exponent<D, N>>>;
}; };
template<BaseDimension D> template<BaseDimension D>
@@ -242,7 +241,7 @@ struct dimension_pow_impl<D, 1> {
}; };
template<BaseDimension D, std::intmax_t N> template<BaseDimension D, std::intmax_t N>
struct dimension_pow_impl<derived_dimension_base<exp<D, 1, N>>, N> { struct dimension_pow_impl<derived_dimension_base<exponent<D, 1, N>>, N> {
using type = D; using type = D;
}; };

View File

@@ -36,28 +36,28 @@ template<ratio R>
constexpr auto ratio_text() constexpr auto ratio_text()
{ {
if constexpr(R.num == 1 && R.den == 1 && R.exp != 0) { if constexpr(R.num == 1 && R.den == 1 && R.exp != 0) {
return base_multiplier + superscript<R.exp>() + basic_fixed_string(" "); return base_multiplier + superscript<R.exp>();
} }
else if constexpr(R.num != 1 || R.den != 1 || R.exp != 0) { else if constexpr(R.num != 1 || R.den != 1 || R.exp != 0) {
auto txt = basic_fixed_string("[") + regular<R.num>(); auto txt = basic_fixed_string("[") + regular<R.num>();
if constexpr(R.den == 1) { if constexpr(R.den == 1) {
if constexpr(R.exp == 0) { if constexpr(R.exp == 0) {
return txt + basic_fixed_string("] "); return txt + basic_fixed_string("]");
} }
else { else {
return txt + " " + base_multiplier + superscript<R.exp>() + return txt + " " + base_multiplier + superscript<R.exp>() +
basic_fixed_string("] "); basic_fixed_string("]");
} }
} }
else { else {
if constexpr(R.exp == 0) { if constexpr(R.exp == 0) {
return txt + basic_fixed_string("/") + regular<R.den>() + return txt + basic_fixed_string("/") + regular<R.den>() +
basic_fixed_string("] "); basic_fixed_string("]");
} }
else { else {
return txt + basic_fixed_string("/") + regular<R.den>() + return txt + basic_fixed_string("/") + regular<R.den>() +
" " + base_multiplier + superscript<R.exp>() + " " + base_multiplier + superscript<R.exp>() +
basic_fixed_string("] "); basic_fixed_string("]");
} }
} }
} }
@@ -66,7 +66,7 @@ constexpr auto ratio_text()
} }
} }
template<ratio R, typename PrefixFamily> template<ratio R, typename PrefixFamily, std::size_t SymbolLen>
constexpr auto prefix_or_ratio_text() constexpr auto prefix_or_ratio_text()
{ {
if constexpr(R.num == 1 && R.den == 1 && R.exp == 0) { if constexpr(R.num == 1 && R.den == 1 && R.exp == 0) {
@@ -84,12 +84,20 @@ constexpr auto prefix_or_ratio_text()
} }
else { else {
// print as a ratio of the coherent unit // print as a ratio of the coherent unit
return ratio_text<R>(); constexpr auto txt = ratio_text<R>();
if constexpr(SymbolLen > 0 && txt.standard().size() > 0)
return txt + basic_fixed_string(" ");
else
return txt;
} }
} }
else { else {
// print as a ratio of the coherent unit // print as a ratio of the coherent unit
return ratio_text<R>(); constexpr auto txt = ratio_text<R>();
if constexpr(SymbolLen > 0 && txt.standard().size() > 0)
return txt + basic_fixed_string(" ");
else
return txt;
} }
} }
} }
@@ -97,8 +105,7 @@ constexpr auto prefix_or_ratio_text()
template<typename... Es, std::size_t... Idxs> template<typename... Es, std::size_t... Idxs>
constexpr auto derived_dimension_unit_text(exp_list<Es...>, std::index_sequence<Idxs...>) constexpr auto derived_dimension_unit_text(exp_list<Es...>, std::index_sequence<Idxs...>)
{ {
constexpr auto neg_exp = negative_exp_count<Es...>; return (exp_text<Es, dimension_unit<typename Es::dimension>::symbol, negative_exp_count<Es...>, Idxs>() + ... + basic_symbol_text(basic_fixed_string("")));
return (exp_text<Es, dimension_unit<typename Es::dimension>::symbol, neg_exp, Idxs>() + ...);
} }
template<typename... Es> template<typename... Es>
@@ -129,6 +136,11 @@ constexpr auto exp_list_with_named_units(exp_list<Es...>)
return type_list_join<decltype(exp_list_with_named_units(Es()))...>(); return type_list_join<decltype(exp_list_with_named_units(Es()))...>();
} }
constexpr auto exp_list_with_named_units(exp_list<> empty)
{
return empty;
}
template<Dimension Dim> template<Dimension Dim>
constexpr auto derived_dimension_unit_text() constexpr auto derived_dimension_unit_text()
{ {
@@ -150,15 +162,18 @@ constexpr auto unit_text()
else { else {
// print as a prefix or ratio of a coherent unit // print as a prefix or ratio of a coherent unit
using coherent_unit = dimension_unit<Dim>; using coherent_unit = dimension_unit<Dim>;
auto prefix_txt = prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family>();
if constexpr(has_symbol<coherent_unit>) { if constexpr(has_symbol<coherent_unit>) {
// use predefined coherent unit symbol // use predefined coherent unit symbol
return prefix_txt + coherent_unit::symbol; constexpr auto symbol_text = coherent_unit::symbol;
constexpr auto prefix_txt = prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family, symbol_text.standard().size()>();
return prefix_txt + symbol_text;
} }
else { else {
// use derived dimension ingredients to create a unit symbol // use derived dimension ingredients to create a unit symbol
return prefix_txt + derived_dimension_unit_text<Dim>(); constexpr auto symbol_text = derived_dimension_unit_text<Dim>();
constexpr auto prefix_txt = prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family, symbol_text.standard().size()>();
return prefix_txt + symbol_text;
} }
} }
} }

View File

@@ -128,23 +128,23 @@ concept BaseDimension = detail::is_derived_from_base_dimension<T>;
namespace detail { namespace detail {
template<typename T> template<typename T>
inline constexpr bool is_exp = false; inline constexpr bool is_exponent = false;
} // namespace detail } // namespace detail
/** /**
* @brief A concept matching dimension's exponents. * @brief A concept matching dimension's exponents.
* *
* Satisfied by all specializations of :class:`exp`. * Satisfied by all specializations of :class:`exponent`.
*/ */
template<typename T> template<typename T>
concept Exponent = detail::is_exp<T>; concept Exponent = detail::is_exponent<T>;
// DerivedDimension // DerivedDimension
namespace detail { namespace detail {
template<Exponent E, Exponent... ERest> template<Exponent... Es>
requires (BaseDimension<typename E::dimension> && ... && BaseDimension<typename ERest::dimension>) requires (BaseDimension<typename Es::dimension> && ...)
struct derived_dimension_base; struct derived_dimension_base;
} // namespace detail } // namespace detail

View File

@@ -30,7 +30,7 @@
namespace units::data { namespace units::data {
struct bit_per_second : unit<bit_per_second> {}; struct bit_per_second : unit<bit_per_second> {};
struct dim_bitrate : derived_dimension<dim_bitrate, bit_per_second, exp<dim_information, 1>, exp<physical::si::dim_time, -1>> {}; struct dim_bitrate : derived_dimension<dim_bitrate, bit_per_second, exponent<dim_information, 1>, exponent<physical::si::dim_time, -1>> {};
struct kibibit_per_second : deduced_unit<kibibit_per_second, dim_bitrate, kibibit, physical::si::second> {}; struct kibibit_per_second : deduced_unit<kibibit_per_second, dim_bitrate, kibibit, physical::si::second> {};
struct mebibit_per_second : deduced_unit<mebibit_per_second, dim_bitrate, mebibit, physical::si::second> {}; struct mebibit_per_second : deduced_unit<mebibit_per_second, dim_bitrate, mebibit, physical::si::second> {};

View File

@@ -29,7 +29,7 @@
#include <units/bits/dim_unpack.h> #include <units/bits/dim_unpack.h>
#include <units/bits/external/downcasting.h> #include <units/bits/external/downcasting.h>
#include <units/bits/external/type_list.h> #include <units/bits/external/type_list.h>
#include <units/exp.h> #include <units/exponent.h>
namespace units { namespace units {
@@ -75,12 +75,11 @@ using make_dimension = TYPENAME to_derived_dimension_base<typename dim_consolida
* *
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam U a coherent unit of a derived dimension * @tparam U a coherent unit of a derived dimension
* @tparam E the list of exponents of ingredient dimensions * @tparam Es the list of exponents of ingredient dimensions
* @tparam ERest the list of exponents of ingredient dimensions
*/ */
template<typename Child, Unit U, Exponent E, Exponent... ERest> template<typename Child, Unit U, Exponent... Es>
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<E, ERest...>> { struct derived_dimension : downcast_child<Child, typename detail::make_dimension<Es...>> {
using recipe = exp_list<E, ERest...>; using recipe = exp_list<Es...>;
using coherent_unit = U; using coherent_unit = U;
static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents()); static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents());
}; };

View File

@@ -0,0 +1,46 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/quantity_cast.h>
namespace units {
struct unitless : named_unit<unitless, "", no_prefix> {};
struct percent : named_scaled_unit<percent, "%", no_prefix, ratio(1, 100), unitless> {};
/**
* @brief Dimension one
*
* Dimension for which all the exponents of the factors corresponding to the base
* dimensions are zero. Also commonly named as "dimensionless".
*/
struct dim_one : derived_dimension<dim_one, unitless> {};
template<typename T>
concept Dimensionless = QuantityOf<T, dim_one>;
template<Unit U, Scalar Rep = double>
using dimensionless = quantity<dim_one, U, Rep>;
} // namespace units

View File

@@ -35,17 +35,17 @@ namespace units {
* @tparam Den denominator of the factor * @tparam Den denominator of the factor
*/ */
template<Dimension Dim, std::intmax_t Num, std::intmax_t Den = 1> template<Dimension Dim, std::intmax_t Num, std::intmax_t Den = 1>
struct exp { struct exponent {
using dimension = Dim; using dimension = Dim;
static constexpr int num = Num; static constexpr int num = Num;
static constexpr int den = Den; static constexpr int den = Den;
}; };
// is_exp // is_exponent
namespace detail { namespace detail {
template<typename Dim, std::intmax_t Num, std::intmax_t Den> template<typename Dim, std::intmax_t Num, std::intmax_t Den>
inline constexpr bool is_exp<exp<Dim, Num, Den>> = true; inline constexpr bool is_exponent<exponent<Dim, Num, Den>> = true;
} // namespace detail } // namespace detail
@@ -58,7 +58,7 @@ struct exp_less : base_dimension_less<typename E1::dimension, typename E2::dimen
namespace detail { namespace detail {
template<typename Dim, std::intmax_t Num, std::intmax_t Den> template<typename Dim, std::intmax_t Num, std::intmax_t Den>
constexpr exp<Dim, -Num, Den> exp_invert_impl(exp<Dim, Num, Den>); constexpr exponent<Dim, -Num, Den> exp_invert_impl(exponent<Dim, Num, Den>);
} // namespace detail } // namespace detail
@@ -71,7 +71,7 @@ namespace detail {
template<Exponent E, std::intmax_t Num, std::intmax_t Den> template<Exponent E, std::intmax_t Num, std::intmax_t Den>
struct exp_multiply_impl { struct exp_multiply_impl {
static constexpr ratio r = ratio(E::num, E::den) * ratio(Num, Den); static constexpr ratio r = ratio(E::num, E::den) * ratio(Num, Den);
using type = exp<typename E::dimension, r.num, r.den>; using type = exponent<typename E::dimension, r.num, r.den>;
}; };
} // namespace detail } // namespace detail

View File

@@ -79,6 +79,19 @@ inline Quantity AUTO sqrt(const Q& q) noexcept
return quantity<dim, unit, rep>(static_cast<rep>(std::sqrt(q.count()))); return quantity<dim, unit, rep>(static_cast<rep>(std::sqrt(q.count())));
} }
/**
* @brief Computes Euler's raised to the given power
*
* @param q Quantity being the base of the operation
* @return Quantity The value of the same quantity type
*/
template<typename D, typename U, typename Rep>
inline quantity<D, U, Rep> exp(const quantity<D, U, Rep>& q)
{
using coherent_unit = dimension_unit<D>;
return quantity_cast<U>(quantity<D, coherent_unit, Rep>(std::exp(quantity_cast<coherent_unit>(q).count())));
}
/** /**
* @brief Computes the absolute value of a quantity * @brief Computes the absolute value of a quantity
* *
@@ -86,7 +99,7 @@ inline Quantity AUTO sqrt(const Q& q) noexcept
* @return Quantity The absolute value of a provided quantity * @return Quantity The absolute value of a provided quantity
*/ */
template<Quantity Q> template<Quantity Q>
constexpr Quantity AUTO abs(const Q& q) noexcept inline Quantity AUTO abs(const Q& q) noexcept
requires requires { std::abs(q.count()); } requires requires { std::abs(q.count()); }
{ {
return Q(std::abs(q.count())); return Q(std::abs(q.count()));

View File

@@ -65,126 +65,126 @@ struct dim_angle : base_dimension<"A", U> {};
template<typename Child, Unit U, DimensionOf<dim_angle> A, DimensionOf<dim_time> T> template<typename Child, Unit U, DimensionOf<dim_angle> A, DimensionOf<dim_time> T>
struct dim_angular_velocity : derived_dimension<Child, U, exp<A, 1>, exp<T, -1>> {}; struct dim_angular_velocity : derived_dimension<Child, U, exponent<A, 1>, exponent<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_time> T> template<typename Child, Unit U, DimensionOf<dim_time> T>
struct dim_frequency : derived_dimension<Child, U, exp<T, -1>> {}; struct dim_frequency : derived_dimension<Child, U, exponent<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_length> L>
struct dim_area : derived_dimension<Child, U, exp<L, 2>> {}; struct dim_area : derived_dimension<Child, U, exponent<L, 2>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_length> L>
struct dim_volume : derived_dimension<Child, U, exp<L, 3>> {}; struct dim_volume : derived_dimension<Child, U, exponent<L, 3>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T> template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T>
struct dim_speed : derived_dimension<Child, U, exp<L, 1>, exp<T, -1>> {}; struct dim_speed : derived_dimension<Child, U, exponent<L, 1>, exponent<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T> template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T>
struct dim_acceleration : derived_dimension<Child, U, exp<L, 1>, exp<T, -2>> {}; struct dim_acceleration : derived_dimension<Child, U, exponent<L, 1>, exponent<T, -2>> {};
template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_acceleration> A> template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_acceleration> A>
struct dim_force : derived_dimension<Child, U, exp<M, 1>, exp<A, 1>> {}; struct dim_force : derived_dimension<Child, U, exponent<M, 1>, exponent<A, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_speed> V> template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_speed> V>
struct dim_momentum : derived_dimension<Child, U, exp<M, 1>, exp<V, 1>> {}; struct dim_momentum : derived_dimension<Child, U, exponent<M, 1>, exponent<V, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L>
struct dim_energy : derived_dimension<Child, U, exp<F, 1>, exp<L, 1>> {}; struct dim_energy : derived_dimension<Child, U, exponent<F, 1>, exponent<L, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_angle> A> template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_angle> A>
struct dim_torque : derived_dimension<Child, U, exp<E, 1>, exp<A, 1>> {}; struct dim_torque : derived_dimension<Child, U, exponent<E, 1>, exponent<A, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_length> L>
struct dim_density : derived_dimension<Child, U, exp<M, 1>, exp<L, -3>> {}; struct dim_density : derived_dimension<Child, U, exponent<M, 1>, exponent<L, -3>> {};
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_time> T> template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_time> T>
struct dim_power : derived_dimension<Child, U, exp<E, 1>, exp<T, -1>> {}; struct dim_power : derived_dimension<Child, U, exponent<E, 1>, exponent<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_power> P, DimensionOf<dim_electric_current> C> template<typename Child, Unit U, DimensionOf<dim_power> P, DimensionOf<dim_electric_current> C>
struct dim_voltage : derived_dimension<Child, U, exp<P, 1>, exp<C, -1>> {}; struct dim_voltage : derived_dimension<Child, U, exponent<P, 1>, exponent<C, -1>> {};
template <typename Child, Unit U, DimensionOf<dim_voltage> V, DimensionOf<dim_electric_current> C> template <typename Child, Unit U, DimensionOf<dim_voltage> V, DimensionOf<dim_electric_current> C>
struct dim_resistance : derived_dimension<Child,U, exp<V, 1>, exp<C, -1>> {}; struct dim_resistance : derived_dimension<Child,U, exponent<V, 1>, exponent<C, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_time> T, DimensionOf<dim_electric_current> C> template<typename Child, Unit U, DimensionOf<dim_time> T, DimensionOf<dim_electric_current> C>
struct dim_electric_charge : derived_dimension<Child, U, exp<T, 1>, exp<C, 1>> {}; struct dim_electric_charge : derived_dimension<Child, U, exponent<T, 1>, exponent<C, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_electric_charge> C, DimensionOf<dim_voltage> V> template<typename Child, Unit U, DimensionOf<dim_electric_charge> C, DimensionOf<dim_voltage> V>
struct dim_capacitance : derived_dimension<Child, U, exp<C, 1>, exp<V, -1>> {}; struct dim_capacitance : derived_dimension<Child, U, exponent<C, 1>, exponent<V, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L>
struct dim_surface_tension : derived_dimension<Child, U, exp<F, 1>, exp<L, -1>> {}; struct dim_surface_tension : derived_dimension<Child, U, exponent<F, 1>, exponent<L, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_area> A> template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_area> A>
struct dim_pressure : derived_dimension<Child, U, exp<F, 1>, exp<A, -1>> {}; struct dim_pressure : derived_dimension<Child, U, exponent<F, 1>, exponent<A, -1>> {};
template <typename Child, Unit U, DimensionOf<dim_voltage> V, DimensionOf<dim_time> T, DimensionOf<dim_length> L> template <typename Child, Unit U, DimensionOf<dim_voltage> V, DimensionOf<dim_time> T, DimensionOf<dim_length> L>
struct dim_magnetic_induction : derived_dimension<Child, U, exp<V, 1>, exp<T, 1>, exp<L, -2>> {}; struct dim_magnetic_induction : derived_dimension<Child, U, exponent<V, 1>, exponent<T, 1>, exponent<L, -2>> {};
template<typename Child, Unit U, DimensionOf<dim_magnetic_induction> B, DimensionOf<dim_area> A> template<typename Child, Unit U, DimensionOf<dim_magnetic_induction> B, DimensionOf<dim_area> A>
struct dim_magnetic_flux : derived_dimension<Child, U, exp<B, 1>, exp<A, 1>> {}; struct dim_magnetic_flux : derived_dimension<Child, U, exponent<B, 1>, exponent<A, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_magnetic_flux> F, DimensionOf<dim_electric_current> I> template<typename Child, Unit U, DimensionOf<dim_magnetic_flux> F, DimensionOf<dim_electric_current> I>
struct dim_inductance : derived_dimension<Child, U, exp<F, 1>, exp<I, -1>> {}; struct dim_inductance : derived_dimension<Child, U, exponent<F, 1>, exponent<I, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_resistance> R> template<typename Child, Unit U, DimensionOf<dim_resistance> R>
struct dim_conductance : derived_dimension<Child, U, exp<R, -1>> {}; struct dim_conductance : derived_dimension<Child, U, exponent<R, -1>> {};
// TODO Add when downcasting issue is solved // TODO Add when downcasting issue is solved
// template<typename Child, Unit U, DimensionOf<dim_time> T> // template<typename Child, Unit U, DimensionOf<dim_time> T>
// struct dim_radioactivity : derived_dimension<Child, U, exp<T, -1>> {}; // struct dim_radioactivity : derived_dimension<Child, U, exponent<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_time> T, DimensionOf<dim_substance> M> template<typename Child, Unit U, DimensionOf<dim_time> T, DimensionOf<dim_substance> M>
struct dim_catalytic_activity : derived_dimension<Child, U, exp<T, -1>, exp<M, 1>> {}; struct dim_catalytic_activity : derived_dimension<Child, U, exponent<T, -1>, exponent<M, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_mass> M> template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_mass> M>
struct dim_absorbed_dose : derived_dimension<Child, U, exp<E, 1>, exp<M, -1>> {}; struct dim_absorbed_dose : derived_dimension<Child, U, exponent<E, 1>, exponent<M, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_electric_current> I, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_electric_current> I, DimensionOf<dim_length> L>
struct dim_current_density : derived_dimension<Child, U, exp<I, 1>, exp<L, -2>> {}; struct dim_current_density : derived_dimension<Child, U, exponent<I, 1>, exponent<L, -2>> {};
template<typename Child, Unit U, DimensionOf<dim_substance> M, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_substance> M, DimensionOf<dim_length> L>
struct dim_concentration : derived_dimension<Child, U, exp<M, 1>, exp<L, -3>> {}; struct dim_concentration : derived_dimension<Child, U, exponent<M, 1>, exponent<L, -3>> {};
template<typename Child, Unit U, DimensionOf<dim_luminous_intensity> I, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_luminous_intensity> I, DimensionOf<dim_length> L>
struct dim_luminance : derived_dimension<Child, U, exp<I, 1>, exp<L, -2>> {}; struct dim_luminance : derived_dimension<Child, U, exponent<I, 1>, exponent<L, -2>> {};
template<typename Child, Unit U, DimensionOf<dim_pressure> P, DimensionOf<dim_time> T> template<typename Child, Unit U, DimensionOf<dim_pressure> P, DimensionOf<dim_time> T>
struct dim_dynamic_viscosity : derived_dimension<Child, U, exp<P, 1>, exp<T, 1>> {}; struct dim_dynamic_viscosity : derived_dimension<Child, U, exponent<P, 1>, exponent<T, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_thermodynamic_temperature> T> template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_thermodynamic_temperature> T>
struct dim_heat_capacity : derived_dimension<Child, U, exp<E, 1>, exp<T, -1>> {}; struct dim_heat_capacity : derived_dimension<Child, U, exponent<E, 1>, exponent<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_heat_capacity> C, DimensionOf<dim_mass> M> template<typename Child, Unit U, DimensionOf<dim_heat_capacity> C, DimensionOf<dim_mass> M>
struct dim_specific_heat_capacity : derived_dimension<Child, U, exp<C, 1>, exp<M, -1>> {}; struct dim_specific_heat_capacity : derived_dimension<Child, U, exponent<C, 1>, exponent<M, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_heat_capacity> C, DimensionOf<dim_substance> M> template<typename Child, Unit U, DimensionOf<dim_heat_capacity> C, DimensionOf<dim_substance> M>
struct dim_molar_heat_capacity : derived_dimension<Child, U, exp<C, 1>, exp<M, -1>> {}; struct dim_molar_heat_capacity : derived_dimension<Child, U, exponent<C, 1>, exponent<M, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_power> P, DimensionOf<dim_length> L, DimensionOf<dim_thermodynamic_temperature> T> template<typename Child, Unit U, DimensionOf<dim_power> P, DimensionOf<dim_length> L, DimensionOf<dim_thermodynamic_temperature> T>
struct dim_thermal_conductivity : derived_dimension<Child, U, exp<P, 1>, exp<L, -1>, exp<T, -1>> {}; struct dim_thermal_conductivity : derived_dimension<Child, U, exponent<P, 1>, exponent<L, -1>, exponent<T, -1>> {};
// TODO Add when downcasting issue is solved // TODO Add when downcasting issue is solved
// template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_length> L> // template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_length> L>
// struct dim_energy_density : derived_dimension<Child, U, exp<E, 1>, exp<L, -3>> {}; // struct dim_energy_density : derived_dimension<Child, U, exponent<E, 1>, exponent<L, -3>> {};
template<typename Child, Unit U, DimensionOf<dim_voltage> V, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_voltage> V, DimensionOf<dim_length> L>
struct dim_electric_field_strength : derived_dimension<Child, U, exp<V, 1>, exp<L, -1>> {}; struct dim_electric_field_strength : derived_dimension<Child, U, exponent<V, 1>, exponent<L, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_electric_charge> Q, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_electric_charge> Q, DimensionOf<dim_length> L>
struct dim_charge_density : derived_dimension<Child, U, exp<Q, 1>, exp<L, -3>> {}; struct dim_charge_density : derived_dimension<Child, U, exponent<Q, 1>, exponent<L, -3>> {};
template<typename Child, Unit U, DimensionOf<dim_electric_charge> Q, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_electric_charge> Q, DimensionOf<dim_length> L>
struct dim_surface_charge_density : derived_dimension<Child, U, exp<Q, 1>, exp<L, -2>> {}; struct dim_surface_charge_density : derived_dimension<Child, U, exponent<Q, 1>, exponent<L, -2>> {};
template<typename Child, Unit U, DimensionOf<dim_capacitance> C, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_capacitance> C, DimensionOf<dim_length> L>
struct dim_permittivity : derived_dimension<Child, U, exp<C, 1>, exp<L, -1>> {}; struct dim_permittivity : derived_dimension<Child, U, exponent<C, 1>, exponent<L, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_inductance> H, DimensionOf<dim_length> L> template<typename Child, Unit U, DimensionOf<dim_inductance> H, DimensionOf<dim_length> L>
struct dim_permeability : derived_dimension<Child, U, exp<H, 1>, exp<L, -1>> {}; struct dim_permeability : derived_dimension<Child, U, exponent<H, 1>, exponent<L, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_substance> M> template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_substance> M>
struct dim_molar_energy : derived_dimension<Child, U, exp<E, 1>, exp<M, -1>> {}; struct dim_molar_energy : derived_dimension<Child, U, exponent<E, 1>, exponent<M, -1>> {};
template<typename T> template<typename T>
concept Length = QuantityOf<T, dim_length>; concept Length = QuantityOf<T, dim_length>;

View File

@@ -27,6 +27,7 @@
#include <units/bits/dimension_op.h> #include <units/bits/dimension_op.h>
#include <units/bits/pow.h> #include <units/bits/pow.h>
#include <units/bits/to_string.h> #include <units/bits/to_string.h>
#include <units/dimensionless.h>
#include <units/quantity_cast.h> #include <units/quantity_cast.h>
#if COMP_MSVC || COMP_GCC >= 10 #if COMP_MSVC || COMP_GCC >= 10
@@ -76,7 +77,7 @@ public:
template<Scalar Value> template<Scalar Value>
requires detail::safe_convertible<Value, rep> requires detail::safe_convertible<Value, rep>
constexpr explicit quantity(const Value& v) : value_{static_cast<rep>(v)} {} constexpr explicit(!(std::is_same_v<dimension, dim_one> && std::is_same_v<unit, unitless>)) quantity(const Value& v) : value_{static_cast<rep>(v)} {}
template<Quantity Q2> template<Quantity Q2>
requires equivalent_dim<D, typename Q2::dimension> && requires equivalent_dim<D, typename Q2::dimension> &&
@@ -220,6 +221,123 @@ public:
// Hidden Friends // Hidden Friends
// Below friend functions are to be found via argument-dependent lookup only // Below friend functions are to be found via argument-dependent lookup only
[[nodiscard]] friend constexpr quantity operator+(const quantity& lhs, const quantity& rhs)
requires std::regular_invocable<std::plus<>, Rep, Rep>
{
return quantity(lhs.count() + rhs.count());
}
template<typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator+(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
requires std::regular_invocable<std::plus<>, Rep, Rep2>
{
using common_rep = decltype(lhs.count() + rhs.count());
using ret = common_quantity<quantity, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() + ret(rhs).count());
}
[[nodiscard]] friend constexpr quantity operator-(const quantity& lhs, const quantity& rhs)
requires std::regular_invocable<std::minus<>, Rep, Rep>
{
return quantity(lhs.count() - rhs.count());
}
template<typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator-(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
requires std::regular_invocable<std::minus<>, Rep, Rep2>
{
using common_rep = decltype(lhs.count() - rhs.count());
using ret = common_quantity<quantity, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() - ret(rhs).count());
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator*(const quantity& q, const Value& v)
requires std::regular_invocable<std::multiplies<>, Rep, Value>
{
using common_rep = decltype(q.count() * v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() * v);
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator*(const Value& v, const quantity& q)
requires std::regular_invocable<std::multiplies<>, Value, Rep>
{
return q * v;
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator*(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::multiplies<>, Rep, Rep2>
{
using dim = dimension_multiply<D, D2>;
using ret_unit = downcast_unit<dim, (U::ratio / dimension_unit<D>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<dim, ret_unit, common_rep>;
return ret(lhs.count() * rhs.count());
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator/(const Value& v, const quantity& q)
requires std::regular_invocable<std::divides<>, Value, Rep>
{
Expects(q.count() != 0);
using dim = dim_invert<D>;
using ret_unit = downcast_unit<dim, ratio(U::ratio.den, U::ratio.num, -U::ratio.exp)>;
using common_rep = decltype(v / q.count());
using ret = quantity<dim, ret_unit, common_rep>;
return ret(v / q.count());
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator/(const quantity& q, const Value& v)
requires std::regular_invocable<std::divides<>, Rep, Value>
{
Expects(v != Value{0});
using common_rep = decltype(q.count() / v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() / v);
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator/(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::divides<>, Rep, Rep2>
{
Expects(rhs.count() != 0);
using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide<D, D2>;
using ret_unit = downcast_unit<dim, (U::ratio / dimension_unit<D>::ratio) / (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
using ret = quantity<dim, ret_unit, common_rep>;
return ret(lhs.count() / rhs.count());
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator%(const quantity& q, const Value& v)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Value>) &&
std::regular_invocable<std::modulus<>, Rep, Value>
{
using common_rep = decltype(q.count() % v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() % v);
}
template<typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator%(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Rep2>) &&
std::regular_invocable<std::modulus<>, Rep, Rep2>
{
using common_rep = decltype(lhs.count() % rhs.count());
using ret = common_quantity<quantity, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() % ret(rhs).count());
}
#if COMP_MSVC || COMP_GCC >= 10 #if COMP_MSVC || COMP_GCC >= 10
template<typename D2, typename U2, typename Rep2> template<typename D2, typename U2, typename Rep2>
@@ -301,136 +419,6 @@ public:
} }
}; };
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator+(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires std::regular_invocable<std::plus<>, Rep1, Rep2>
{
using common_rep = decltype(lhs.count() + rhs.count());
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() + ret(rhs).count());
}
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator-(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires std::regular_invocable<std::minus<>, Rep1, Rep2>
{
using common_rep = decltype(lhs.count() - rhs.count());
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() - ret(rhs).count());
}
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<D, U, Rep>& q, const Value& v)
requires std::regular_invocable<std::multiplies<>, Rep, Value>
{
using common_rep = decltype(q.count() * v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() * v);
}
template<Scalar Value, typename D, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity<D, U, Rep>& q)
requires std::regular_invocable<std::multiplies<>, Value, Rep>
{
return q * v;
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::multiplies<>, Rep1, Rep2> &&
equivalent_dim<D1, dim_invert<D2>>
{
using common_rep = decltype(lhs.count() * rhs.count());
const ratio r = U1::ratio * U2::ratio;
if constexpr (treat_as_floating_point<common_rep>) {
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
} else {
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::ipow10(r.exp)) / static_cast<common_rep>(r.den);
}
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::multiplies<>, Rep1, Rep2>
{
using dim = dimension_multiply<D1, D2>;
using unit = downcast_unit<dim, (U1::ratio / dimension_unit<D1>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<dim, unit, common_rep>;
return ret(lhs.count() * rhs.count());
}
template<Scalar Value, typename D, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity<D, U, Rep>& q)
requires std::regular_invocable<std::divides<>, Value, Rep>
{
Expects(q.count() != 0);
using dim = dim_invert<D>;
using unit = downcast_unit<dim, ratio(U::ratio.den, U::ratio.num, -U::ratio.exp)>;
using common_rep = decltype(v / q.count());
using ret = quantity<dim, unit, common_rep>;
return ret(v / q.count());
}
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D, U, Rep>& q, const Value& v)
requires std::regular_invocable<std::divides<>, Rep, Value>
{
Expects(v != Value{0});
using common_rep = decltype(q.count() / v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() / v);
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::divides<>, Rep1, Rep2> &&
equivalent_dim<D1, D2>
{
Expects(rhs.count() != 0);
using common_rep = decltype(lhs.count() / rhs.count());
using cq = common_quantity<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, common_rep>;
return cq(lhs).count() / cq(rhs).count();
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::divides<>, Rep1, Rep2>
{
Expects(rhs.count() != 0);
using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide<D1, D2>;
using unit = downcast_unit<dim, (U1::ratio / dimension_unit<D1>::ratio) / (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
using ret = quantity<dim, unit, common_rep>;
return ret(lhs.count() / rhs.count());
}
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<D, U, Rep>& q, const Value& v)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Value>) &&
std::regular_invocable<std::modulus<>, Rep, Value>
{
using common_rep = decltype(q.count() % v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() % v);
}
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep1>) &&
(!treat_as_floating_point<Rep2>) &&
std::regular_invocable<std::modulus<>, Rep1, Rep2>
{
using common_rep = decltype(lhs.count() % rhs.count());
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() % ret(rhs).count());
}
namespace detail { namespace detail {
template<typename D, typename U, typename Rep> template<typename D, typename U, typename Rep>

View File

@@ -27,8 +27,6 @@
#include <units/bits/dimension_op.h> #include <units/bits/dimension_op.h>
#include <units/bits/external/type_traits.h> #include <units/bits/external/type_traits.h>
#include <units/bits/pow.h> #include <units/bits/pow.h>
#include <units/quantity.h>
#include <units/quantity_point.h>
#include <cassert> #include <cassert>
#ifdef _MSC_VER #ifdef _MSC_VER
@@ -38,6 +36,12 @@
namespace units { namespace units {
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity;
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity_point;
namespace detail { namespace detail {
template<typename D, typename U, typename Rep> template<typename D, typename U, typename Rep>
@@ -284,8 +288,8 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
template<typename Q1, typename Q2> template<typename Q1, typename Q2>
constexpr ratio cast_ratio(const Q1& from, const Q2& to) constexpr ratio cast_ratio(const Q1& from, const Q2& to)
{ {
using FromU = Q1::unit; using FromU = TYPENAME Q1::unit;
using ToU = Q2::unit; using ToU = TYPENAME Q2::unit;
if constexpr(same_unit_reference<FromU, ToU>::value) { if constexpr(same_unit_reference<FromU, ToU>::value) {
return FromU::ratio / ToU::ratio; return FromU::ratio / ToU::ratio;
} }

View File

@@ -8,7 +8,7 @@ struct test<%= k %> {
#if defined(METABENCH) #if defined(METABENCH)
using dim = units::make_dimension_t<<%= using dim = units::make_dimension_t<<%=
xs = ((1)..(n)).map { |j| "units::exp<dim#{j}, 1>" } xs = ((1)..(n)).map { |j| "units::exponent<dim#{j}, 1>" }
rng = Random.new(k) rng = Random.new(k)
xs.shuffle(random: rng).join(', ') xs.shuffle(random: rng).join(', ')
%>>; %>>;

View File

@@ -8,7 +8,7 @@ struct test<%= k %> {
#if defined(METABENCH) #if defined(METABENCH)
using dim = units::make_dimension_t<<%= using dim = units::make_dimension_t<<%=
xs = ((1)..(n)).map { |j| "units::exp<dim#{j}, 1>" } xs = ((1)..(n)).map { |j| "units::exponent<dim#{j}, 1>" }
rng = Random.new(k) rng = Random.new(k)
xs.shuffle(random: rng).join(', ') xs.shuffle(random: rng).join(', ')
%>>; %>>;

View File

@@ -60,26 +60,26 @@ namespace units {
struct base_dimension_less : std::bool_constant<D1 < D2> { struct base_dimension_less : std::bool_constant<D1 < D2> {
}; };
// exp // exponent
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den = 1> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den = 1>
struct exp { struct exponent {
static constexpr const base_dimension& dimension = BaseDimension; static constexpr const base_dimension& dimension = BaseDimension;
static constexpr std::intmax_t num = Num; static constexpr std::intmax_t num = Num;
static constexpr std::intmax_t den = Den; static constexpr std::intmax_t den = Den;
}; };
// is_exp // is_exponent
namespace detail { namespace detail {
template<typename T> template<typename T>
inline constexpr bool is_exp = false; inline constexpr bool is_exponent = false;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
inline constexpr bool is_exp<exp<BaseDimension, Num, Den>> = true; inline constexpr bool is_exponent<exponent<BaseDimension, Num, Den>> = true;
} // namespace detail } // namespace detail
template<typename T> template<typename T>
concept Exponent = detail::is_exp<T>; concept Exponent = detail::is_exponent<T>;
// exp_dim_id_less // exp_dim_id_less
@@ -93,8 +93,8 @@ namespace units {
struct exp_invert; struct exp_invert;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
struct exp_invert<exp<BaseDimension, Num, Den>> { struct exp_invert<exponent<BaseDimension, Num, Den>> {
using type = exp<BaseDimension, -Num, Den>; using type = exponent<BaseDimension, -Num, Den>;
}; };
template<Exponent E> template<Exponent E>
@@ -161,12 +161,12 @@ namespace units {
}; };
template<const base_dimension& D, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, Exponent... ERest> template<const base_dimension& D, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, Exponent... ERest>
struct dim_consolidate<dimension<exp<D, Num1, Den1>, exp<D, Num2, Den2>, ERest...>> { struct dim_consolidate<dimension<exponent<D, Num1, Den1>, exponent<D, Num2, Den2>, ERest...>> {
using r1 = std::ratio<Num1, Den1>; using r1 = std::ratio<Num1, Den1>;
using r2 = std::ratio<Num2, Den2>; using r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>; using r = std::ratio_add<r1, r2>;
using type = conditional<r::num == 0, dim_consolidate_t<dimension<ERest...>>, using type = conditional<r::num == 0, dim_consolidate_t<dimension<ERest...>>,
dim_consolidate_t<dimension<exp<D, r::num, r::den>, ERest...>>>; dim_consolidate_t<dimension<exponent<D, r::num, r::den>, ERest...>>>;
}; };
} // namespace detail } // namespace detail

View File

@@ -60,26 +60,26 @@ namespace units {
struct base_dimension_less : std::bool_constant<D1 < D2> { struct base_dimension_less : std::bool_constant<D1 < D2> {
}; };
// exp // exponent
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den = 1> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den = 1>
struct exp { struct exponent {
static constexpr const base_dimension& dimension = BaseDimension; static constexpr const base_dimension& dimension = BaseDimension;
static constexpr int num = Num; static constexpr int num = Num;
static constexpr int den = Den; static constexpr int den = Den;
}; };
// is_exp // is_exponent
namespace detail { namespace detail {
template<typename T> template<typename T>
inline constexpr bool is_exp = false; inline constexpr bool is_exponent = false;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
inline constexpr bool is_exp<exp<BaseDimension, Num, Den>> = true; inline constexpr bool is_exponent<exponent<BaseDimension, Num, Den>> = true;
} // namespace detail } // namespace detail
template<typename T> template<typename T>
concept Exponent = detail::is_exp<T>; concept Exponent = detail::is_exponent<T>;
// exp_dim_id_less // exp_dim_id_less
@@ -93,8 +93,8 @@ namespace units {
struct exp_invert; struct exp_invert;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
struct exp_invert<exp<BaseDimension, Num, Den>> { struct exp_invert<exponent<BaseDimension, Num, Den>> {
using type = exp<BaseDimension, -Num, Den>; using type = exponent<BaseDimension, -Num, Den>;
}; };
template<Exponent E> template<Exponent E>
@@ -161,12 +161,12 @@ namespace units {
}; };
template<const base_dimension& D, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest> template<const base_dimension& D, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest>
struct dim_consolidate<dimension<exp<D, Num1, Den1>, exp<D, Num2, Den2>, ERest...>> { struct dim_consolidate<dimension<exponent<D, Num1, Den1>, exponent<D, Num2, Den2>, ERest...>> {
using r1 = std::ratio<Num1, Den1>; using r1 = std::ratio<Num1, Den1>;
using r2 = std::ratio<Num2, Den2>; using r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>; using r = std::ratio_add<r1, r2>;
using type = conditional<r::num == 0, dim_consolidate_t<dimension<ERest...>>, using type = conditional<r::num == 0, dim_consolidate_t<dimension<ERest...>>,
dim_consolidate_t<dimension<exp<D, r::num, r::den>, ERest...>>>; dim_consolidate_t<dimension<exponent<D, r::num, r::den>, ERest...>>>;
}; };
} // namespace detail } // namespace detail

View File

@@ -60,10 +60,10 @@ namespace units {
struct base_dimension_less : std::bool_constant<D1 < D2> { struct base_dimension_less : std::bool_constant<D1 < D2> {
}; };
// exp // exponent
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den = 1> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den = 1>
struct exp { struct exponent {
static constexpr const base_dimension& dimension = BaseDimension; static constexpr const base_dimension& dimension = BaseDimension;
static constexpr std::intmax_t num = Num; static constexpr std::intmax_t num = Num;
static constexpr std::intmax_t den = Den; static constexpr std::intmax_t den = Den;
@@ -81,8 +81,8 @@ namespace units {
struct exp_invert; struct exp_invert;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den> template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
struct exp_invert<exp<BaseDimension, Num, Den>> { struct exp_invert<exponent<BaseDimension, Num, Den>> {
using type = exp<BaseDimension, -Num, Den>; using type = exponent<BaseDimension, -Num, Den>;
}; };
template<typename E> template<typename E>
@@ -132,12 +132,12 @@ namespace units {
}; };
template<const base_dimension& D, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest> template<const base_dimension& D, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest>
struct dim_consolidate<dimension<exp<D, Num1, Den1>, exp<D, Num2, Den2>, ERest...>> { struct dim_consolidate<dimension<exponent<D, Num1, Den1>, exponent<D, Num2, Den2>, ERest...>> {
using r1 = std::ratio<Num1, Den1>; using r1 = std::ratio<Num1, Den1>;
using r2 = std::ratio<Num2, Den2>; using r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>; using r = std::ratio_add<r1, r2>;
using type = conditional<r::num == 0, dim_consolidate_t<dimension<ERest...>>, using type = conditional<r::num == 0, dim_consolidate_t<dimension<ERest...>>,
dim_consolidate_t<dimension<exp<D, r::num, r::den>, ERest...>>>; dim_consolidate_t<dimension<exponent<D, r::num, r::den>, ERest...>>>;
}; };
} // namespace detail } // namespace detail

View File

@@ -8,7 +8,7 @@ struct test<%= k %> {
#if defined(METABENCH) #if defined(METABENCH)
using dim = units::make_dimension_t<<%= using dim = units::make_dimension_t<<%=
xs = ((1)..(n)).map { |j| "units::exp<dim#{j}, 1>" } xs = ((1)..(n)).map { |j| "units::exponent<dim#{j}, 1>" }
rng = Random.new(k) rng = Random.new(k)
xs.shuffle(random: rng).join(', ') xs.shuffle(random: rng).join(', ')
%>>; %>>;

View File

@@ -421,6 +421,72 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
} }
} }
SECTION("dimensionless quantity")
{
SECTION("unitless with ratio == 1")
{
const auto q = 4q_m / 2q_m;
os << q;
SECTION("iostream")
{
CHECK(os.str() == "2");
}
SECTION("fmt with default format {} on a quantity")
{
CHECK(fmt::format("{}", q) == os.str());
}
SECTION("fmt with format {:%Q %q} on a quantity")
{
CHECK(fmt::format("{:%Q %q}", q) == "2 ");
}
}
SECTION("unitless with ratio.exp != 0")
{
const auto q = 4q_km / 2q_m;
os << q;
SECTION("iostream")
{
CHECK(os.str() == "2 × 10³");
}
SECTION("fmt with default format {} on a quantity")
{
CHECK(fmt::format("{}", q) == os.str());
}
SECTION("fmt with format {:%Q %q} on a quantity")
{
CHECK(fmt::format("{:%Q %q}", q) == "2 × 10³");
}
}
SECTION("percents")
{
const auto q = quantity_cast<percent>(15.q_m / 100.q_m);
os << q;
SECTION("iostream")
{
CHECK(os.str() == "15 %");
}
SECTION("fmt with default format {} on a quantity")
{
CHECK(fmt::format("{}", q) == os.str());
}
SECTION("fmt with format {:%Q %q} on a quantity")
{
CHECK(fmt::format("{:%Q %q}", q) == os.str());
}
}
}
SECTION("quantity with an unkown dimension") SECTION("quantity with an unkown dimension")
{ {
SECTION("unit::ratio::num == 1 && unit::ratio::den == 1") SECTION("unit::ratio::num == 1 && unit::ratio::den == 1")
@@ -573,7 +639,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
} }
} }
SECTION("exp::num == 1 && exp::den == 1") SECTION("exponent::num == 1 && exponent::den == 1")
{ {
const auto q = 4q_m * 2q_s; const auto q = 4q_m * 2q_s;
os << q; os << q;
@@ -594,7 +660,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
} }
} }
SECTION("exp::num == 2 && exp::den == 1 for positive exponent") SECTION("exponent::num == 2 && exponent::den == 1 for positive exponent")
{ {
const auto q = 4q_m * 2q_s * 2q_s; const auto q = 4q_m * 2q_s * 2q_s;
os << q; os << q;
@@ -615,7 +681,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
} }
} }
SECTION("exp::num == 2 && exp::den == 1 for negative exponent (first dimension)") SECTION("exponent::num == 2 && exponent::den == 1 for negative exponent (first dimension)")
{ {
const auto q = 8q_s / 2q_m / 2q_m; const auto q = 8q_s / 2q_m / 2q_m;
os << q; os << q;
@@ -636,7 +702,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
} }
} }
SECTION("exp::num == 2 && exp::den == 1 for negative exponent (not first dimension)") SECTION("exponent::num == 2 && exponent::den == 1 for negative exponent (not first dimension)")
{ {
const auto q = 8q_m / 2q_kg / 2q_kg; const auto q = 8q_m / 2q_kg / 2q_kg;
os << q; os << q;

View File

@@ -63,10 +63,12 @@ TEST_CASE("absolute functions on quantity returns the absolute value", "[math][a
REQUIRE(abs(-1q_m) == 1q_m); REQUIRE(abs(-1q_m) == 1q_m);
} }
#ifndef COMP_MSVC
SECTION ("floating-point representation") SECTION ("floating-point representation")
{ {
REQUIRE(abs(-1.q_m) == 1q_m); REQUIRE(abs(-1.q_m) == 1q_m);
} }
#endif
} }
SECTION ("'abs()' on a positive quantity returns the abs") SECTION ("'abs()' on a positive quantity returns the abs")
@@ -76,10 +78,12 @@ TEST_CASE("absolute functions on quantity returns the absolute value", "[math][a
REQUIRE(abs(1q_m) == 1q_m); REQUIRE(abs(1q_m) == 1q_m);
} }
#ifndef COMP_MSVC
SECTION ("floating-point representation") SECTION ("floating-point representation")
{ {
REQUIRE(abs(1.q_m) == 1q_m); REQUIRE(abs(1.q_m) == 1q_m);
} }
#endif
} }
} }

View File

@@ -33,14 +33,14 @@ using namespace units::physical::si;
// power spectral density // power spectral density
struct sq_volt_per_hertz : unit<sq_volt_per_hertz> {}; struct sq_volt_per_hertz : unit<sq_volt_per_hertz> {};
struct dim_power_spectral_density : derived_dimension<dim_power_spectral_density, sq_volt_per_hertz, units::exp<dim_voltage, 2>, units::exp<dim_frequency, -1>> {}; struct dim_power_spectral_density : derived_dimension<dim_power_spectral_density, sq_volt_per_hertz, units::exponent<dim_voltage, 2>, units::exponent<dim_frequency, -1>> {};
template<Unit U, Scalar Rep = double> template<Unit U, Scalar Rep = double>
using power_spectral_density = quantity<dim_power_spectral_density, U, Rep>; using power_spectral_density = quantity<dim_power_spectral_density, U, Rep>;
// amplitude spectral density // amplitude spectral density
struct volt_per_sqrt_hertz : unit<volt_per_sqrt_hertz> {}; struct volt_per_sqrt_hertz : unit<volt_per_sqrt_hertz> {};
struct dim_amplitude_spectral_density : derived_dimension<dim_amplitude_spectral_density, volt_per_sqrt_hertz, units::exp<dim_voltage, 1>, units::exp<dim_frequency, -1, 2>> {}; struct dim_amplitude_spectral_density : derived_dimension<dim_amplitude_spectral_density, volt_per_sqrt_hertz, units::exponent<dim_voltage, 1>, units::exponent<dim_frequency, -1, 2>> {};
template<Unit U, Scalar Rep = double> template<Unit U, Scalar Rep = double>
using amplitude_spectral_density = quantity<dim_amplitude_spectral_density, U, Rep>; using amplitude_spectral_density = quantity<dim_amplitude_spectral_density, U, Rep>;
@@ -60,7 +60,7 @@ static_assert(is_same_v<decltype(sqrt(power_spectral_density<sq_volt_per_hertz>(
namespace { namespace {
struct kilogram_per_second : unit<kilogram_per_second> {}; struct kilogram_per_second : unit<kilogram_per_second> {};
struct dim_mass_rate : derived_dimension<dim_mass_rate, kilogram_per_second, units::exp<dim_mass, 1>, units::exp<dim_time, -1>> {}; struct dim_mass_rate : derived_dimension<dim_mass_rate, kilogram_per_second, units::exponent<dim_mass, 1>, units::exponent<dim_time, -1>> {};
struct kilogram_per_hour : deduced_unit<kilogram_per_hour, dim_mass_rate, kilogram, hour> {}; struct kilogram_per_hour : deduced_unit<kilogram_per_hour, dim_mass_rate, kilogram, hour> {};
constexpr auto a = 1q_kg / 1q_h; constexpr auto a = 1q_kg / 1q_h;
static_assert(is_same_v<decltype(a)::unit, kilogram_per_hour>); static_assert(is_same_v<decltype(a)::unit, kilogram_per_hour>);

View File

@@ -39,8 +39,8 @@ struct d3 : base_dimension<"d3", u3> {};
// exp_invert // exp_invert
static_assert(is_same_v<exp_invert<units::exp<d0, 2>>, units::exp<d0, -2>>); static_assert(is_same_v<exp_invert<units::exponent<d0, 2>>, units::exponent<d0, -2>>);
static_assert(is_same_v<exp_invert<units::exp<d1, -2>>, units::exp<d1, 2>>); static_assert(is_same_v<exp_invert<units::exponent<d1, -2>>, units::exponent<d1, 2>>);
// dim_unpack // dim_unpack
@@ -54,66 +54,66 @@ template<Exponent... Es>
using derived_dim = detail::derived_dimension_base<Es...>; using derived_dim = detail::derived_dimension_base<Es...>;
static_assert(is_same_v<dim_unpack<>, exp_list<>>); static_assert(is_same_v<dim_unpack<>, exp_list<>>);
static_assert(is_same_v<dim_unpack<units::exp<d0, 1>>, exp_list<units::exp<d0, 1>>>); static_assert(is_same_v<dim_unpack<units::exponent<d0, 1>>, exp_list<units::exponent<d0, 1>>>);
static_assert(is_same_v<dim_unpack<units::exp<d0, 1>, units::exp<d1, 2>>, exp_list<units::exp<d0, 1>, units::exp<d1, 2>>>); static_assert(is_same_v<dim_unpack<units::exponent<d0, 1>, units::exponent<d1, 2>>, exp_list<units::exponent<d0, 1>, units::exponent<d1, 2>>>);
using dim1 = derived_dim<units::exp<d0, 1>>; using dim1 = derived_dim<units::exponent<d0, 1>>;
using dim2 = derived_dim<units::exp<d0, 1>, units::exp<d1, 2>>; using dim2 = derived_dim<units::exponent<d0, 1>, units::exponent<d1, 2>>;
static_assert(is_same_v<dim_unpack<units::exp<dim1, 2>, units::exp<d0, 1>>, exp_list<units::exp<d0, 2>, units::exp<d0, 1>>>); static_assert(is_same_v<dim_unpack<units::exponent<dim1, 2>, units::exponent<d0, 1>>, exp_list<units::exponent<d0, 2>, units::exponent<d0, 1>>>);
static_assert(is_same_v<dim_unpack<units::exp<dim2, -2>, units::exp<d0, 1>, units::exp<d1, 2>>, static_assert(is_same_v<dim_unpack<units::exponent<dim2, -2>, units::exponent<d0, 1>, units::exponent<d1, 2>>,
exp_list<units::exp<d0, -2>, units::exp<d1, -4>, units::exp<d0, 1>, units::exp<d1, 2>>>); exp_list<units::exponent<d0, -2>, units::exponent<d1, -4>, units::exponent<d0, 1>, units::exponent<d1, 2>>>);
// dim_invert // dim_invert
static_assert(is_same_v<dim_invert<derived_dim<units::exp<d0, -1>>>, d0>); static_assert(is_same_v<dim_invert<derived_dim<units::exponent<d0, -1>>>, d0>);
static_assert(is_same_v<dim_invert<derived_dim<units::exp<d0, -2>>>, unknown_dimension<units::exp<d0, 2>>>); static_assert(is_same_v<dim_invert<derived_dim<units::exponent<d0, -2>>>, unknown_dimension<units::exponent<d0, 2>>>);
static_assert( static_assert(
is_same_v<dim_invert<derived_dim<units::exp<d0, 2>, units::exp<d1, -1>>>, unknown_dimension<units::exp<d0, -2>, units::exp<d1, 1>>>); is_same_v<dim_invert<derived_dim<units::exponent<d0, 2>, units::exponent<d1, -1>>>, unknown_dimension<units::exponent<d0, -2>, units::exponent<d1, 1>>>);
// make_dimension // make_dimension
template<typename... Ts> template<typename... Ts>
using make_dimension = detail::make_dimension<Ts...>; using make_dimension = detail::make_dimension<Ts...>;
static_assert(is_same_v<make_dimension<units::exp<d0, 1>>, derived_dim<units::exp<d0, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d0, 1>>, derived_dim<units::exponent<d0, 1>>>);
static_assert(is_same_v<make_dimension<units::exp<d0, 1>, units::exp<d1, 1>>, derived_dim<units::exp<d0, 1>, units::exp<d1, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>>, derived_dim<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert(is_same_v<make_dimension<units::exp<d1, 1>, units::exp<d0, 1>>, derived_dim<units::exp<d0, 1>, units::exp<d1, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d1, 1>, units::exponent<d0, 1>>, derived_dim<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert(is_same_v<make_dimension<units::exp<d1, 1>, units::exp<d1, 1>>, derived_dim<units::exp<d1, 2>>>); static_assert(is_same_v<make_dimension<units::exponent<d1, 1>, units::exponent<d1, 1>>, derived_dim<units::exponent<d1, 2>>>);
static_assert(is_same_v<make_dimension<units::exp<d1, 1>, units::exp<d1, 1, 2>>, derived_dim<units::exp<d1, 3, 2>>>); static_assert(is_same_v<make_dimension<units::exponent<d1, 1>, units::exponent<d1, 1, 2>>, derived_dim<units::exponent<d1, 3, 2>>>);
static_assert(is_same_v<make_dimension<units::exp<d1, 1, 2>, units::exp<d1, 1, 2>>, derived_dim<units::exp<d1, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d1, 1, 2>, units::exponent<d1, 1, 2>>, derived_dim<units::exponent<d1, 1>>>);
static_assert(is_same_v<make_dimension<units::exp<d1, 2>, units::exp<d1, 1, 2>>, derived_dim<units::exp<d1, 5, 2>>>); static_assert(is_same_v<make_dimension<units::exponent<d1, 2>, units::exponent<d1, 1, 2>>, derived_dim<units::exponent<d1, 5, 2>>>);
static_assert(is_same_v<make_dimension<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d0, 1>, units::exp<d1, 1>>, static_assert(is_same_v<make_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d0, 1>, units::exponent<d1, 1>>,
derived_dim<units::exp<d0, 2>, units::exp<d1, 2>>>); derived_dim<units::exponent<d0, 2>, units::exponent<d1, 2>>>);
static_assert(is_same_v<make_dimension<units::exp<d0, -1>, units::exp<d1, -1>, units::exp<d0, -1>, units::exp<d1, -1>>, static_assert(is_same_v<make_dimension<units::exponent<d0, -1>, units::exponent<d1, -1>, units::exponent<d0, -1>, units::exponent<d1, -1>>,
derived_dim<units::exp<d0, -2>, units::exp<d1, -2>>>); derived_dim<units::exponent<d0, -2>, units::exponent<d1, -2>>>);
static_assert(is_same_v<make_dimension<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d1, -1>>, derived_dim<units::exp<d0, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d1, -1>>, derived_dim<units::exponent<d0, 1>>>);
static_assert(is_same_v<make_dimension<units::exp<d0, 1>, units::exp<d0, -1>, units::exp<d1, 1>>, derived_dim<units::exp<d1, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d0, 1>, units::exponent<d0, -1>, units::exponent<d1, 1>>, derived_dim<units::exponent<d1, 1>>>);
static_assert(is_same_v<make_dimension<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d0, -1>>, derived_dim<units::exp<d1, 1>>>); static_assert(is_same_v<make_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d0, -1>>, derived_dim<units::exponent<d1, 1>>>);
// dimension_multiply // dimension_multiply
static_assert(is_same_v<dimension_multiply<derived_dim<units::exp<d0, 1>>, derived_dim<units::exp<d1, 1>>>, static_assert(is_same_v<dimension_multiply<derived_dim<units::exponent<d0, 1>>, derived_dim<units::exponent<d1, 1>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>>>); unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert( static_assert(
is_same_v<dimension_multiply<derived_dim<units::exp<d0, 1>>, d1>, unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>>>); is_same_v<dimension_multiply<derived_dim<units::exponent<d0, 1>>, d1>, unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert( static_assert(
is_same_v<dimension_multiply<d0, derived_dim<units::exp<d1, 1>>>, unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>>>); is_same_v<dimension_multiply<d0, derived_dim<units::exponent<d1, 1>>>, unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert(is_same_v<dimension_multiply<d0, d1>, unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>>>); static_assert(is_same_v<dimension_multiply<d0, d1>, unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert(is_same_v< static_assert(is_same_v<
dimension_multiply<derived_dim<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d2, 1>>, derived_dim<units::exp<d3, 1>>>, dimension_multiply<derived_dim<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d2, 1>>, derived_dim<units::exponent<d3, 1>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d2, 1>, units::exp<d3, 1>>>); unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d2, 1>, units::exponent<d3, 1>>>);
static_assert(is_same_v< static_assert(is_same_v<
dimension_multiply<derived_dim<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d2, 1>>, derived_dim<units::exp<d1, 1>>>, dimension_multiply<derived_dim<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d2, 1>>, derived_dim<units::exponent<d1, 1>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d1, 2>, units::exp<d2, 1>>>); unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, 2>, units::exponent<d2, 1>>>);
static_assert(is_same_v< static_assert(is_same_v<
dimension_multiply<derived_dim<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d2, 1>>, derived_dim<units::exp<d1, -1>>>, dimension_multiply<derived_dim<units::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d2, 1>>, derived_dim<units::exponent<d1, -1>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d2, 1>>>); unknown_dimension<units::exponent<d0, 1>, units::exponent<d2, 1>>>);
static_assert(is_same_v<dimension_multiply<derived_dim<units::exp<d0, 2>>, derived_dim<units::exp<d0, -1>>>, d0>); static_assert(is_same_v<dimension_multiply<derived_dim<units::exponent<d0, 2>>, derived_dim<units::exponent<d0, -1>>>, d0>);
// dimension_divide // dimension_divide
static_assert(is_same_v<dimension_divide<derived_dim<units::exp<d0, 1>>, derived_dim<units::exp<d1, 1>>>, static_assert(is_same_v<dimension_divide<derived_dim<units::exponent<d0, 1>>, derived_dim<units::exponent<d1, 1>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d1, -1>>>); unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, -1>>>);
static_assert(is_same_v<dimension_divide<derived_dim<units::exp<d0, 2>>, unknown_dimension<units::exp<d0, 1>>>, d0>); static_assert(is_same_v<dimension_divide<derived_dim<units::exponent<d0, 2>>, unknown_dimension<units::exponent<d0, 1>>>, d0>);
} // namespace } // namespace

View File

@@ -161,21 +161,21 @@ static_assert(
static_assert( static_assert(
is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio(36, 1, 2), metre>, int>>); is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio(36, 1, 2), metre>, int>>);
static_assert(is_same_v<decltype(length<metre>() * physical::si::time<minute>()), static_assert(is_same_v<decltype(length<metre>() * physical::si::time<minute>()),
quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6, 1, 1), unknown_coherent_unit>>>); quantity<unknown_dimension<units::exponent<dim_length, 1>, units::exponent<dim_time, 1>>, scaled_unit<ratio(6, 1, 1), unknown_coherent_unit>>>);
static_assert(is_same_v<decltype(1 / physical::si::time<second, int>()), frequency<hertz, int>>); static_assert(is_same_v<decltype(1 / physical::si::time<second, int>()), frequency<hertz, int>>);
static_assert(is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio(1, 6, -1), hertz>, int>>); static_assert(is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio(1, 6, -1), hertz>, int>>);
static_assert(is_same_v<decltype(1 / frequency<hertz, int>()), physical::si::time<second, int>>); static_assert(is_same_v<decltype(1 / frequency<hertz, int>()), physical::si::time<second, int>>);
static_assert(is_same_v<decltype(1 / length<kilometre>()), static_assert(is_same_v<decltype(1 / length<kilometre>()),
quantity<unknown_dimension<units::exp<dim_length, -1>>, scaled_unit<ratio(1, 1, -3), unknown_coherent_unit>>>); quantity<unknown_dimension<units::exponent<dim_length, -1>>, scaled_unit<ratio(1, 1, -3), unknown_coherent_unit>>>);
static_assert(is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>); static_assert(is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
static_assert(is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>); static_assert(is_same_v<decltype(length<metre, int>() / length<metre, double>()), dimensionless<unitless, double>>);
static_assert(is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>); static_assert(is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), dimensionless<scaled_unit<ratio(1, 1, 3), unitless>, double>>);
static_assert( static_assert(
is_same_v<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>); is_same_v<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>);
static_assert( static_assert(
is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio(1, 6, -1), metre_per_second>>>); is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio(1, 6, -1), metre_per_second>>>);
static_assert(is_same_v<decltype(physical::si::time<minute>() / length<metre>()), static_assert(is_same_v<decltype(physical::si::time<minute>() / length<metre>()),
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6 ,1 , 1), unknown_coherent_unit>>>); quantity<unknown_dimension<units::exponent<dim_length, -1>, units::exponent<dim_time, 1>>, scaled_unit<ratio(6 ,1 , 1), unknown_coherent_unit>>>);
static_assert(is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>); static_assert(is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
static_assert(is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>); static_assert(is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
@@ -186,14 +186,27 @@ static_assert((1q_km - 1q_m).count() == 999);
static_assert((2q_m * 2).count() == 4); static_assert((2q_m * 2).count() == 4);
static_assert((3 * 3q_m).count() == 9); static_assert((3 * 3q_m).count() == 9);
static_assert((4q_m / 2).count() == 2); static_assert((4q_m / 2).count() == 2);
static_assert(4q_m / 2q_m == 2); static_assert((4q_km / 2q_m).count() == 2);
static_assert(4q_km / 2000q_m == 2); static_assert((4000q_m / 2q_m).count() == 2000);
static_assert((7q_m % 2).count() == 1); static_assert((7q_m % 2).count() == 1);
static_assert((7q_m % 2q_m).count() == 1); static_assert((7q_m % 2q_m).count() == 1);
static_assert((7q_km % 2000q_m).count() == 1000); static_assert((7q_km % 2000q_m).count() == 1000);
static_assert((10q_km2 * 10q_km2) / 50q_km2 == 2q_km2); static_assert((10q_km2 * 10q_km2) / 50q_km2 == 2q_km2);
constexpr auto q1 = 10q_km / 5q_m;
static_assert(std::is_same_v<decltype(q1), const dimensionless<scaled_unit<ratio(1, 1, 3), unitless>, std::int64_t>>);
static_assert(q1.count() == 2);
constexpr dimensionless<unitless> q2 = q1;
static_assert(q2.count() == 2000);
static_assert(quantity_cast<unitless>(q1).count() == 2000);
constexpr auto q3 = 10q_s * 2q_kHz;
static_assert(std::is_same_v<decltype(q3), const dimensionless<scaled_unit<ratio(1, 1, 3), unitless>, std::int64_t>>);
static_assert(q3.count() == 20);
// comparators // comparators
static_assert(2q_m + 1q_m == 3q_m); static_assert(2q_m + 1q_m == 3q_m);
@@ -264,6 +277,37 @@ static_assert(quantity_cast<metre>(2q_km).count() == 2000);
static_assert(quantity_cast<kilometre>(2000q_m).count() == 2); static_assert(quantity_cast<kilometre>(2000q_m).count() == 2);
static_assert(quantity_cast<int>(1.23q_m).count() == 1); static_assert(quantity_cast<int>(1.23q_m).count() == 1);
// dimensionless
static_assert(std::is_convertible_v<double, dimensionless<unitless>>);
static_assert(std::is_convertible_v<float, dimensionless<unitless>>);
static_assert(!std::is_convertible_v<double, dimensionless<unitless, int>>);
static_assert(std::is_convertible_v<int, dimensionless<unitless>>);
static_assert(!std::is_convertible_v<double, dimensionless<scaled_unit<ratio(1, 1, 1), unitless>>>);
static_assert(std::is_constructible_v<dimensionless<scaled_unit<ratio(1, 1, 1), unitless>>, double>);
static_assert(dimensionless<unitless>(1.23) + dimensionless<unitless>(1.23) == dimensionless<unitless>(2.46));
static_assert(dimensionless<unitless>(1.23) + dimensionless<unitless>(1.23) == 2.46);
static_assert(dimensionless<unitless>(1.23) + 1.23 == 2.46);
static_assert(1.23 + dimensionless<unitless>(1.23) == 2.46);
static_assert(dimensionless<unitless>(1) + 1 == 2);
static_assert(dimensionless<unitless, int>(1) + 1 == 2);
template<typename Rep>
concept invalid_dimensionless_operation = requires()
{
!requires(dimensionless<unitless, Rep> d) { d + 1.23; };
!requires(dimensionless<unitless, Rep> d) { 1.23 + d; };
!requires(dimensionless<scaled_unit<ratio(1, 1, 1), unitless>, Rep> d) { 1 + d; };
!requires(dimensionless<scaled_unit<ratio(1, 1, 1), unitless>, Rep> d) { d + 1; };
};
static_assert(invalid_dimensionless_operation<int>);
static_assert(quantity_cast<percent>(50.q_m / 100.q_m).count() == 50);
static_assert(50.q_m / 100.q_m == dimensionless<percent>(50));
// time // time
static_assert(1q_h == 3600q_s); static_assert(1q_h == 3600q_s);

View File

@@ -40,7 +40,9 @@ static_assert(1q_hm == 100q_m);
static_assert(1q_au == 149'597'870'700q_m); static_assert(1q_au == 149'597'870'700q_m);
static_assert(1q_km + 1q_m == 1001q_m); static_assert(1q_km + 1q_m == 1001q_m);
static_assert(10q_km / 5q_km == 2); static_assert(10q_km / 5q_km == 2);
static_assert(100q_mm / 5q_cm == 2); static_assert(10q_km / 5q_km < 3);
static_assert(100q_mm / 5q_cm == dimensionless<scaled_unit<ratio(1, 1, -1), unitless>>(20));
static_assert(100q_mm / 5q_cm == dimensionless<unitless>(2));
static_assert(10q_km / 2 == 5q_km); static_assert(10q_km / 2 == 5q_km);
static_assert(millimetre::symbol == "mm"); static_assert(millimetre::symbol == "mm");
@@ -102,7 +104,8 @@ static_assert(120 / 1q_min == 2q_Hz);
static_assert(1000 / 1q_s == 1q_kHz); static_assert(1000 / 1q_s == 1q_kHz);
static_assert(1 / 1q_ms == 1q_kHz); static_assert(1 / 1q_ms == 1q_kHz);
static_assert(3.2q_GHz == 3'200'000'000q_Hz); static_assert(3.2q_GHz == 3'200'000'000q_Hz);
static_assert(10q_Hz * 1q_min == 600); static_assert(10q_Hz * 1q_min == dimensionless<scaled_unit<ratio(60), unitless>>(10));
static_assert(10q_Hz * 1q_min == dimensionless<unitless>(600));
static_assert(2 / 1q_Hz == 2q_s); static_assert(2 / 1q_Hz == 2q_s);
// force // force

View File

@@ -98,20 +98,20 @@ struct d0 : base_dimension<"d0", u0> {};
struct u1 : named_unit<u1, "u1", no_prefix> {}; struct u1 : named_unit<u1, "u1", no_prefix> {};
struct d1 : base_dimension<"d1", u1> {}; struct d1 : base_dimension<"d1", u1> {};
static_assert(is_same_v<type_list_merge_sorted<type_list<units::exp<d0, 1>>, type_list<units::exp<d1, 1>>, exp_less>, static_assert(is_same_v<type_list_merge_sorted<type_list<units::exponent<d0, 1>>, type_list<units::exponent<d1, 1>>, exp_less>,
type_list<units::exp<d0, 1>, units::exp<d1, 1>>>); type_list<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
static_assert(is_same_v<type_list_merge_sorted<type_list<units::exp<d1, 1>>, type_list<units::exp<d0, 1>>, exp_less>, static_assert(is_same_v<type_list_merge_sorted<type_list<units::exponent<d1, 1>>, type_list<units::exponent<d0, 1>>, exp_less>,
type_list<units::exp<d0, 1>, units::exp<d1, 1>>>); type_list<units::exponent<d0, 1>, units::exponent<d1, 1>>>);
// type_list_sort // type_list_sort
template<TypeList List> template<TypeList List>
using exp_sort = type_list_sort<List, exp_less>; using exp_sort = type_list_sort<List, exp_less>;
static_assert(is_same_v<exp_sort<exp_list<units::exp<d0, 1>>>, exp_list<units::exp<d0, 1>>>); static_assert(is_same_v<exp_sort<exp_list<units::exponent<d0, 1>>>, exp_list<units::exponent<d0, 1>>>);
static_assert( static_assert(
is_same_v<exp_sort<exp_list<units::exp<d0, 1>, units::exp<d1, -1>>>, exp_list<units::exp<d0, 1>, units::exp<d1, -1>>>); is_same_v<exp_sort<exp_list<units::exponent<d0, 1>, units::exponent<d1, -1>>>, exp_list<units::exponent<d0, 1>, units::exponent<d1, -1>>>);
static_assert( static_assert(
is_same_v<exp_sort<exp_list<units::exp<d1, 1>, units::exp<d0, -1>>>, exp_list<units::exp<d0, -1>, units::exp<d1, 1>>>); is_same_v<exp_sort<exp_list<units::exponent<d1, 1>, units::exponent<d0, -1>>>, exp_list<units::exponent<d0, -1>, units::exponent<d1, 1>>>);
} // namespace } // namespace

View File

@@ -46,7 +46,7 @@ static_assert([]<Prefix P>(P) { return !requires { typename prefixed_unit<struct
#endif #endif
struct metre_per_second : unit<metre_per_second> {}; struct metre_per_second : unit<metre_per_second> {};
struct dim_speed : derived_dimension<dim_speed, metre_per_second, units::exp<dim_length, 1>, units::exp<dim_time, -1>> {}; struct dim_speed : derived_dimension<dim_speed, metre_per_second, units::exponent<dim_length, 1>, units::exponent<dim_time, -1>> {};
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_speed, kilometre, hour> {}; struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
static_assert(is_same_v<downcast<scaled_unit<ratio(1), metre>>, metre>); static_assert(is_same_v<downcast<scaled_unit<ratio(1), metre>>, metre>);