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 committed 2020-09-08 11:02:16 +02:00
1 parent c8b60b80c1
commit 563b358d5e
47 files changed
+599 -422

No files matched your search

@@ -8,7 +8,7 @@ struct test<%= k %> {
#if defined(METABENCH)
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)
xs.shuffle(random: rng).join(', ')
%>>;
@@ -8,7 +8,7 @@ struct test<%= k %> {
#if defined(METABENCH)
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)
xs.shuffle(random: rng).join(', ')
%>>;
@@ -60,26 +60,26 @@ namespace units {
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>
struct exp {
struct exponent {
static constexpr const base_dimension& dimension = BaseDimension;
static constexpr std::intmax_t num = Num;
static constexpr std::intmax_t den = Den;
};
// is_exp
// is_exponent
namespace detail {
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>
inline constexpr bool is_exp<exp<BaseDimension, Num, Den>> = true;
inline constexpr bool is_exponent<exponent<BaseDimension, Num, Den>> = true;
} // namespace detail
template<typename T>
concept Exponent = detail::is_exp<T>;
concept Exponent = detail::is_exponent<T>;
// exp_dim_id_less
@@ -93,8 +93,8 @@ namespace units {
struct exp_invert;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
struct exp_invert<exp<BaseDimension, Num, Den>> {
using type = exp<BaseDimension, -Num, Den>;
struct exp_invert<exponent<BaseDimension, Num, Den>> {
using type = exponent<BaseDimension, -Num, Den>;
};
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>
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 r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>;
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
@@ -60,26 +60,26 @@ namespace units {
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>
struct exp {
struct exponent {
static constexpr const base_dimension& dimension = BaseDimension;
static constexpr int num = Num;
static constexpr int den = Den;
};
// is_exp
// is_exponent
namespace detail {
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>
inline constexpr bool is_exp<exp<BaseDimension, Num, Den>> = true;
inline constexpr bool is_exponent<exponent<BaseDimension, Num, Den>> = true;
} // namespace detail
template<typename T>
concept Exponent = detail::is_exp<T>;
concept Exponent = detail::is_exponent<T>;
// exp_dim_id_less
@@ -93,8 +93,8 @@ namespace units {
struct exp_invert;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
struct exp_invert<exp<BaseDimension, Num, Den>> {
using type = exp<BaseDimension, -Num, Den>;
struct exp_invert<exponent<BaseDimension, Num, Den>> {
using type = exponent<BaseDimension, -Num, Den>;
};
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>
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 r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>;
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
@@ -60,10 +60,10 @@ namespace units {
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>
struct exp {
struct exponent {
static constexpr const base_dimension& dimension = BaseDimension;
static constexpr std::intmax_t num = Num;
static constexpr std::intmax_t den = Den;
@@ -81,8 +81,8 @@ namespace units {
struct exp_invert;
template<const base_dimension& BaseDimension, std::intmax_t Num, std::intmax_t Den>
struct exp_invert<exp<BaseDimension, Num, Den>> {
using type = exp<BaseDimension, -Num, Den>;
struct exp_invert<exponent<BaseDimension, Num, Den>> {
using type = exponent<BaseDimension, -Num, Den>;
};
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>
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 r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>;
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
@@ -8,7 +8,7 @@ struct test<%= k %> {
#if defined(METABENCH)
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)
xs.shuffle(random: rng).join(', ')
%>>;
+70 -4
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("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;
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;
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;
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;
os << q;
+4
View File
@@ -63,10 +63,12 @@ TEST_CASE("absolute functions on quantity returns the absolute value", "[math][a
REQUIRE(abs(-1q_m) == 1q_m);
}
#ifndef COMP_MSVC
SECTION ("floating-point representation")
{
REQUIRE(abs(-1.q_m) == 1q_m);
}
#endif
}
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);
}
#ifndef COMP_MSVC
SECTION ("floating-point representation")
{
REQUIRE(abs(1.q_m) == 1q_m);
}
#endif
}
}
+3 -3
View File
@@ -33,14 +33,14 @@ using namespace units::physical::si;
// power spectral density
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>
using power_spectral_density = quantity<dim_power_spectral_density, U, Rep>;
// amplitude spectral density
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>
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 {
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> {};
constexpr auto a = 1q_kg / 1q_h;
static_assert(is_same_v<decltype(a)::unit, kilogram_per_hour>);
+41 -41
View File
@@ -39,8 +39,8 @@ struct d3 : base_dimension<"d3", u3> {};
// 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::exp<d1, -2>>, units::exp<d1, 2>>);
static_assert(is_same_v<exp_invert<units::exponent<d0, 2>>, units::exponent<d0, -2>>);
static_assert(is_same_v<exp_invert<units::exponent<d1, -2>>, units::exponent<d1, 2>>);
// dim_unpack
@@ -54,66 +54,66 @@ template<Exponent... 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<units::exp<d0, 1>>, exp_list<units::exp<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>>>);
using dim1 = derived_dim<units::exp<d0, 1>>;
using dim2 = derived_dim<units::exp<d0, 1>, units::exp<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::exp<dim2, -2>, units::exp<d0, 1>, units::exp<d1, 2>>,
exp_list<units::exp<d0, -2>, units::exp<d1, -4>, units::exp<d0, 1>, units::exp<d1, 2>>>);
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::exponent<d0, 1>, units::exponent<d1, 2>>, exp_list<units::exponent<d0, 1>, units::exponent<d1, 2>>>);
using dim1 = derived_dim<units::exponent<d0, 1>>;
using dim2 = derived_dim<units::exponent<d0, 1>, units::exponent<d1, 2>>;
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::exponent<dim2, -2>, units::exponent<d0, 1>, units::exponent<d1, 2>>,
exp_list<units::exponent<d0, -2>, units::exponent<d1, -4>, units::exponent<d0, 1>, units::exponent<d1, 2>>>);
// 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::exp<d0, -2>>>, unknown_dimension<units::exp<d0, 2>>>);
static_assert(is_same_v<dim_invert<derived_dim<units::exponent<d0, -1>>>, d0>);
static_assert(is_same_v<dim_invert<derived_dim<units::exponent<d0, -2>>>, unknown_dimension<units::exponent<d0, 2>>>);
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
template<typename... 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::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::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::exp<d1, 1>, units::exp<d1, 1>>, derived_dim<units::exp<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::exp<d1, 1, 2>, units::exp<d1, 1, 2>>, derived_dim<units::exp<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<d0, 1>>, derived_dim<units::exponent<d0, 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::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::exponent<d1, 1>, units::exponent<d1, 1>>, derived_dim<units::exponent<d1, 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::exponent<d1, 1, 2>, units::exponent<d1, 1, 2>>, derived_dim<units::exponent<d1, 1>>>);
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>>,
derived_dim<units::exp<d0, 2>, units::exp<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>>,
derived_dim<units::exp<d0, -2>, units::exp<d1, -2>>>);
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::exponent<d0, 2>, units::exponent<d1, 2>>>);
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::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::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::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<d1, -1>>, derived_dim<units::exponent<d0, 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::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d0, -1>>, derived_dim<units::exponent<d1, 1>>>);
// dimension_multiply
static_assert(is_same_v<dimension_multiply<derived_dim<units::exp<d0, 1>>, derived_dim<units::exp<d1, 1>>>,
unknown_dimension<units::exp<d0, 1>, 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::exponent<d0, 1>, units::exponent<d1, 1>>>);
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(
is_same_v<dimension_multiply<d0, derived_dim<units::exp<d1, 1>>>, unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>>>);
static_assert(is_same_v<dimension_multiply<d0, d1>, 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::exponent<d0, 1>, units::exponent<d1, 1>>>);
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>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d1, 1>, units::exp<d2, 1>, 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::exponent<d0, 1>, units::exponent<d1, 1>, units::exponent<d2, 1>, units::exponent<d3, 1>>>);
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>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d1, 2>, units::exp<d2, 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::exponent<d0, 1>, units::exponent<d1, 2>, units::exponent<d2, 1>>>);
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>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<d2, 1>>>);
static_assert(is_same_v<dimension_multiply<derived_dim<units::exp<d0, 2>>, derived_dim<units::exp<d0, -1>>>, d0>);
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::exponent<d0, 1>, units::exponent<d2, 1>>>);
static_assert(is_same_v<dimension_multiply<derived_dim<units::exponent<d0, 2>>, derived_dim<units::exponent<d0, -1>>>, d0>);
// dimension_divide
static_assert(is_same_v<dimension_divide<derived_dim<units::exp<d0, 1>>, derived_dim<units::exp<d1, 1>>>,
unknown_dimension<units::exp<d0, 1>, units::exp<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, 1>>, derived_dim<units::exponent<d1, 1>>>,
unknown_dimension<units::exponent<d0, 1>, units::exponent<d1, -1>>>);
static_assert(is_same_v<dimension_divide<derived_dim<units::exponent<d0, 2>>, unknown_dimension<units::exponent<d0, 1>>>, d0>);
} // namespace
+51 -7
View File
@@ -161,21 +161,21 @@ 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>>);
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<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 / 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>() / length<metre, double>()), double>);
static_assert(is_same_v<decltype(length<kilometre, 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>()), dimensionless<scaled_unit<ratio(1, 1, 3), unitless>, double>>);
static_assert(
is_same_v<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>);
static_assert(
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>()),
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>() % 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((3 * 3q_m).count() == 9);
static_assert((4q_m / 2).count() == 2);
static_assert(4q_m / 2q_m == 2);
static_assert(4q_km / 2000q_m == 2);
static_assert((4q_km / 2q_m).count() == 2);
static_assert((4000q_m / 2q_m).count() == 2000);
static_assert((7q_m % 2).count() == 1);
static_assert((7q_m % 2q_m).count() == 1);
static_assert((7q_km % 2000q_m).count() == 1000);
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
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<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
static_assert(1q_h == 3600q_s);
+5 -2
View File
@@ -40,7 +40,9 @@ static_assert(1q_hm == 100q_m);
static_assert(1q_au == 149'597'870'700q_m);
static_assert(1q_km + 1q_m == 1001q_m);
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(millimetre::symbol == "mm");
@@ -102,7 +104,8 @@ static_assert(120 / 1q_min == 2q_Hz);
static_assert(1000 / 1q_s == 1q_kHz);
static_assert(1 / 1q_ms == 1q_kHz);
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);
// force
+7 -7
View File
@@ -98,20 +98,20 @@ struct d0 : base_dimension<"d0", u0> {};
struct u1 : named_unit<u1, "u1", no_prefix> {};
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>,
type_list<units::exp<d0, 1>, units::exp<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>,
type_list<units::exp<d0, 1>, units::exp<d1, 1>>>);
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::exponent<d0, 1>, units::exponent<d1, 1>>>);
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::exponent<d0, 1>, units::exponent<d1, 1>>>);
// type_list_sort
template<TypeList List>
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(
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(
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
+1 -1
View File
@@ -46,7 +46,7 @@ static_assert([]<Prefix P>(P) { return !requires { typename prefixed_unit<struct
#endif
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> {};
static_assert(is_same_v<downcast<scaled_unit<ratio(1), metre>>, metre>);