NTTP ratio support added (resolves #49)

This commit is contained in:
Mateusz Pusz committed 2020-06-27 19:15:46 +02:00
1 parent 03facbefd2
commit d171f5451e
47 files changed
+504 -664

No files matched your search

+2 -2
View File
@@ -115,7 +115,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
{
SECTION("in terms of base units")
{
const length<scaled_unit<ratio<1, 1, 6>, metre>> q(123);
const length<scaled_unit<ratio(1, 1, 6), metre>> q(123);
os << q;
SECTION("iostream")
@@ -136,7 +136,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
SECTION("in terms of derived units")
{
const energy<scaled_unit<ratio<1, 1, -2>, joule>> q(60);
const energy<scaled_unit<ratio(1, 1, -2), joule>> q(60);
os << q;
SECTION("iostream")
+2 -2
View File
@@ -319,7 +319,7 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
SECTION("unknown scaled unit with reference different than the dimension's coherent unit")
{
CHECK(fmt::format("{}", mass<units::scaled_unit<units::ratio<2, 3>, gram>>(1)) == "1 [2/3 × 10⁻³] kg");
CHECK(fmt::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio<2, 3>, gram>>(1)) == "1 [2/3 x 10^-3] kg");
CHECK(fmt::format("{}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 × 10⁻³] kg");
CHECK(fmt::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 x 10^-3] kg");
}
}
+1 -1
View File
@@ -57,7 +57,7 @@ static_assert(10q_cm == 2q_cm_per_s * 5q_s);
static_assert(detail::unit_text<dim_speed, centimetre_per_second>() == "cm/s");
// area
static_assert(std::is_same_v<ratio_divide<centimetre::ratio, dimension_unit<dim_length>::ratio>, ratio<1>>);
static_assert(centimetre::ratio / dimension_unit<dim_length>::ratio == ratio(1));
static_assert(1q_cm * 1q_cm == 1q_cm2);
static_assert(100q_cm2 / 10q_cm == 10q_cm);
+1 -1
View File
@@ -57,7 +57,7 @@ static_assert(10q_ft == 2q_ft_per_s * 5q_s);
static_assert(detail::unit_text<dim_speed, foot_per_second>() == "ft/s");
// area
static_assert(std::is_same_v<ratio_divide<foot::ratio, dimension_unit<dim_length>::ratio>, ratio<1>>);
static_assert(foot::ratio / dimension_unit<dim_length>::ratio == ratio(1));
static_assert(1q_ft * 1q_ft == 1q_ft2);
static_assert(100q_ft2 / 10q_ft == 10q_ft);
@@ -209,7 +209,7 @@ static_assert(std::equality_comparable_with<decltype(quantity_point(1q_m)), decl
// quantity_cast
static_assert(
std::is_same_v<decltype(quantity_point_cast<scaled_unit<ratio<1>, metre>>(quantity_point(2q_km)))::unit, metre>);
std::is_same_v<decltype(quantity_point_cast<scaled_unit<ratio(1), metre>>(quantity_point(2q_km)))::unit, metre>);
static_assert(quantity_point_cast<quantity_point<dim_length, metre, int>>(quantity_point(2q_km)).relative().count() ==
2000);
+8 -8
View File
@@ -39,7 +39,7 @@ using namespace units::physical::si;
// constexpr quantity<si::dim_length, second, int> error(0); // should not compile (unit of a different dimension)
// constexpr quantity<si::dim_length, metre, quantity<si::dim_length, metre, int>> error(0); // should not compile (quantity used as Rep)
// constexpr quantity<metre, si::dim_length, double> error(0); // should not compile (reordered arguments)
// constexpr quantity<si::dim_length, scaled_unit<ratio<-1, 1>, metre>, int> error(0); // should not compile (negative unit ratio)
// constexpr quantity<si::dim_length, scaled_unit<ratio(-1, 1), metre>, int> error(0); // should not compile (negative unit ratio)
// member types
@@ -138,23 +138,23 @@ static_assert(std::is_same_v<decltype(1.0 * length<metre, int>()), length<metre,
static_assert(
std::is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<second, int>()), length<metre, int>>);
static_assert(
std::is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio<36, 1, 2>, metre>, int>>);
std::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(std::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::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6, 1, 1), unknown_coherent_unit>>>);
static_assert(std::is_same_v<decltype(1 / physical::si::time<second, int>()), frequency<hertz, int>>);
static_assert(std::is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio<1, 6, -1>, hertz>, int>>);
static_assert(std::is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio(1, 6, -1), hertz>, int>>);
static_assert(std::is_same_v<decltype(1 / frequency<hertz, int>()), physical::si::time<second, int>>);
static_assert(std::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::exp<dim_length, -1>>, scaled_unit<ratio(1, 1, -3), unknown_coherent_unit>>>);
static_assert(std::is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
static_assert(std::is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
static_assert(std::is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
static_assert(
std::is_same_v<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>);
static_assert(
std::is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio<1, 6, -1>, metre_per_second>>>);
std::is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio(1, 6, -1), metre_per_second>>>);
static_assert(std::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::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6 ,1 , 1), unknown_coherent_unit>>>);
static_assert(std::is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
static_assert(std::is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
@@ -234,7 +234,7 @@ static_assert(std::equality_comparable_with<decltype(1q_m), decltype(1q_ft_us)>)
// quantity_cast
static_assert(std::is_same_v<decltype(quantity_cast<scaled_unit<ratio<1>, metre>>(2q_km))::unit, metre>);
static_assert(std::is_same_v<decltype(quantity_cast<scaled_unit<ratio(1), metre>>(2q_km))::unit, metre>);
static_assert(quantity_cast<length<metre, int>>(2q_km).count() == 2000);
static_assert(quantity_cast<length<kilometre, int>>(2000q_m).count() == 2);
+76 -94
View File
@@ -1,110 +1,92 @@
// 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.
// 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.
#include "units/ratio.h"
#include "units/ratio.h"
namespace {
namespace {
using namespace units;
using namespace units;
template<Ratio R1, Ratio R2>
inline constexpr bool same = R1::num == R2::num && R1::den == R2::den && R1::exp == R2::exp;
static_assert(ratio(2, 4) == ratio(1, 2));
static_assert(same<ratio<2, 4>, ratio<1, 2>>);
// basic exponents tests
// note use of ::type is required because template params are changed while stamping out template
static_assert(ratio(2, 40, 1) == ratio(1, 20, 1));
static_assert(ratio(20, 4, -1) == ratio(10, 2, -1));
static_assert(ratio(200, 5) == ratio(20'000, 50, -1));
// basic exponents tests
// note use of ::type is required because template params are changed while stamping out template
static_assert(std::is_same_v<ratio<2, 40, 1>::type, ratio<1, 20, 1>::type>);
static_assert(std::is_same_v<ratio<20, 4, -1>::type, ratio<10, 2, -1>::type>);
static_assert(std::is_same_v<ratio<200, 5>::type, ratio<20'000, 50, -1>::type>);
static_assert(ratio(1) * ratio(3, 8) == ratio(3, 8));
static_assert(ratio(3, 8) * ratio(1) == ratio(3, 8));
static_assert(ratio(4) * ratio(1, 8) == ratio(1, 2));
static_assert(ratio(4) * ratio(1, 2) == ratio(2));
static_assert(ratio(1, 8) * ratio(2) == ratio(1, 4));
static_assert(ratio(1, 2) * ratio(8) == ratio(4));
static_assert(std::is_same_v<ratio_multiply<ratio<1>, ratio<3, 8>>, ratio<3, 8>>);
static_assert(std::is_same_v<ratio_multiply<ratio<3, 8>, ratio<1>>, ratio<3, 8>>);
static_assert(std::is_same_v<ratio_multiply<ratio<4>, ratio<1, 8>>, ratio<1, 2>>);
static_assert(std::is_same_v<ratio_multiply<ratio<4>, ratio<1, 2>>, ratio<2>>);
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8>, ratio<2>>, ratio<1, 4>>);
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2>, ratio<8>>, ratio<4>>);
// multiply with exponents
static_assert(ratio(1, 8, 2) * ratio(2, 1, 4) == ratio(1, 4, 6));
static_assert(ratio(1, 2, -4) * ratio(8, 1, 3) == ratio(4, 1, -1));
// multiply with exponents
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8, 2>, ratio<2, 1, 4>>, ratio<1, 4, 6>>);
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2, -4>, ratio<8, 1, 3>>, ratio<4, 1, -1>>);
static_assert(ratio(4) / ratio(2) == ratio(2));
static_assert(ratio(2) / ratio(8) == ratio(1, 4));
static_assert(ratio(1, 8) / ratio(2) == ratio(1, 16));
static_assert(ratio(6) / ratio(3) == ratio(2));
static_assert(std::is_same_v<ratio_divide<ratio<4>, ratio<2>>, ratio<2>>);
static_assert(std::is_same_v<ratio_divide<ratio<2>, ratio<8>>, ratio<1, 4>>);
static_assert(std::is_same_v<ratio_divide<ratio<1, 8>, ratio<2>>, ratio<1, 16>>);
static_assert(std::is_same_v<ratio_divide<ratio<6>, ratio<3>>, ratio<2>>);
// divide with exponents
static_assert(ratio(1, 8, -6) / ratio(2, 1, -8) == ratio(1, 16, 2));
static_assert(ratio(6, 1, 4) / ratio(3) == ratio(2, 1, 4));
// divide with exponents
static_assert(std::is_same_v<ratio_divide<ratio<1, 8, -6>, ratio<2, 1, -8>>, ratio<1, 16, 2>>);
static_assert(std::is_same_v<ratio_divide<ratio<6, 1, 4>, ratio<3>>, ratio<2, 1, 4>>);
static_assert(pow<0>(ratio(2)) == ratio(1));
static_assert(pow<1>(ratio(2)) == ratio(2));
static_assert(pow<2>(ratio(2)) == ratio(4));
static_assert(pow<3>(ratio(2)) == ratio(8));
static_assert(pow<0>(ratio(1, 2)) == ratio(1));
static_assert(pow<1>(ratio(1, 2)) == ratio(1, 2));
static_assert(pow<2>(ratio(1, 2)) == ratio(1, 4));
static_assert(pow<3>(ratio(1, 2)) == ratio(1, 8));
static_assert(std::is_same_v<ratio_pow<ratio<2>, 0>, ratio<1>>);
static_assert(std::is_same_v<ratio_pow<ratio<2>, 1>, ratio<2>>);
static_assert(std::is_same_v<ratio_pow<ratio<2>, 2>, ratio<4>>);
static_assert(std::is_same_v<ratio_pow<ratio<2>, 3>, ratio<8>>);
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 0>, ratio<1>>);
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 1>, ratio<1, 2>>);
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 2>, ratio<1, 4>>);
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 3>, ratio<1, 8>>);
// pow with exponents
static_assert(pow<2>(ratio(1, 2, 3)) == ratio(1, 4, 6));
static_assert(pow<3>(ratio(1, 2, -6)) == ratio(1, 8, -18));
// pow with exponents
static_assert(std::is_same_v<ratio_pow<ratio<1, 2, 3>, 2>, ratio<1, 4, 6>>);
static_assert(std::is_same_v<ratio_pow<ratio<1, 2, -6>, 3>, ratio<1, 8, -18>>);
static_assert(sqrt(ratio(9)) == ratio(3));
static_assert(sqrt(ratio(4)) == ratio(2));
static_assert(sqrt(ratio(1)) == ratio(1));
static_assert(sqrt(ratio(0)) == ratio(0));
static_assert(sqrt(ratio(1, 4)) == ratio(1, 2));
static_assert(std::is_same_v<ratio_sqrt<ratio<9>>, ratio<3>>);
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
static_assert(std::is_same_v<ratio_sqrt<ratio<1>>, ratio<1>>);
static_assert(std::is_same_v<ratio_sqrt<ratio<0>>, ratio<0>>);
static_assert(std::is_same_v<ratio_sqrt<ratio<1, 4>>, ratio<1, 2>>);
// sqrt with exponents
static_assert(sqrt(ratio(9, 1, 2)) == ratio(3, 1, 1));
static_assert(sqrt(ratio(4)) == ratio(2));
// sqrt with exponents
static_assert(std::is_same_v<ratio_sqrt<ratio<9, 1, 2>>, ratio<3, 1, 1>>);
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
// common_ratio
static_assert(common_ratio(ratio(1), ratio(1000)) == ratio(1));
static_assert(common_ratio(ratio(1000), ratio(1)) == ratio(1));
static_assert(common_ratio(ratio(1), ratio(1, 1000)) == ratio(1, 1000));
static_assert(common_ratio(ratio(1, 1000), ratio(1)) == ratio(1, 1000));
static_assert(common_ratio(ratio(100, 1), ratio(10, 1)) == ratio(10, 1));
static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10));
// unused
// static_assert(std::is_same_v<units::ratio_add<units::ratio<1, 2, 0>, units::ratio<1, 3, 0>>, units::ratio<5, 6, 0>>);
// static_assert(std::is_same_v<units::ratio_add<units::ratio<1, 2, 1>, units::ratio<1, 3, 1>>, units::ratio<5, 6, 1>>);
// static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, 2>, units::ratio<2, 7, 2>>, units::ratio<37, 56, 2>>);
// common ratio with exponents
static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1));
static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3));
// static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, 2>, units::ratio<2, 7, 1>>, units::ratio<226, 56, 1>>);
// static_assert(std::is_same_v<units::ratio_add<units::ratio<2, 7, 1>, units::ratio<3, 8, 2>>, units::ratio<226, 56, 1>>);
// static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, -2>, units::ratio<2, 7, -1>>, units::ratio<181, 56, -2>>);
// static_assert(std::is_same_v<units::ratio_add<units::ratio<2, 7, -1>, units::ratio<3, 8, -2>>, units::ratio<181, 56, -2>>);
// common_ratio
// note use of ::type is required because template params are changed while stamping out template
static_assert(std::is_same_v<common_ratio<ratio<1>::type, ratio<1000>>, ratio<1>::type>);
static_assert(std::is_same_v<common_ratio<ratio<1000>, ratio<1>>::type, ratio<1>::type>);
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1000>>::type, ratio<1, 1000>::type>);
static_assert(std::is_same_v<common_ratio<ratio<1, 1000>, ratio<1>>::type, ratio<1, 1000>::type>);
static_assert(std::is_same_v<common_ratio<ratio<100, 1>, ratio<10, 1>>::type, ratio<10, 1>::type>);
static_assert(std::is_same_v<common_ratio<ratio<100, 1>, ratio<1, 10>>::type, ratio<1, 10>::type>);
// common ratio with exponents
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1, 3>>::type, ratio<1>::type>);
static_assert(std::is_same_v<common_ratio<ratio<10, 1, -1>, ratio<1, 1, -3>>::type, ratio<1, 1, -3>::type>);
} // namespace
} // namespace
+1 -1
View File
@@ -237,7 +237,7 @@ static_assert(kilogray::symbol == "kGy");
// speed
static_assert(std::is_same_v<decltype(1q_km / 1q_s), speed<scaled_unit<ratio<1, 1, 3>, metre_per_second>, std::int64_t>>);
static_assert(std::is_same_v<decltype(1q_km / 1q_s), speed<scaled_unit<ratio(1, 1, 3), metre_per_second>, std::int64_t>>);
static_assert(10q_m / 5q_s == 2q_m_per_s);
static_assert(10 / 5q_s * 1q_m == 2q_m_per_s);
+8 -8
View File
@@ -31,12 +31,12 @@ using namespace units::physical;
struct metre : named_unit<metre, "m", si::prefix> {};
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 1, -4>, metre> {};
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio(9'144, 1, -4), metre> {};
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio(1, 3), yard> {};
struct dim_length : base_dimension<"length", metre> {};
struct second : named_unit<second, "s", si::prefix> {};
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<36, 1, 2>, second> {};
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio(36, 1, 2), second> {};
struct dim_time : base_dimension<"time", second> {};
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
@@ -46,11 +46,11 @@ 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 kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1>, metre>>, metre>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1, 1, -2>, metre>>, centimetre>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio<yard::ratio::num, yard::ratio::den, yard::ratio::exp>, metre>>, yard>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio_multiply<typename yard::ratio, ratio<1, 3>>, metre>>, foot>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio_divide<typename kilometre::ratio, typename hour::ratio>, metre_per_second>>, kilometre_per_hour>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio(1), metre>>, metre>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio(1, 1, -2), metre>>, centimetre>);
static_assert(std::is_same_v<downcast<scaled_unit<ratio(yard::ratio.num, yard::ratio.den, yard::ratio.exp), metre>>, yard>);
static_assert(std::is_same_v<downcast<scaled_unit<yard::ratio * ratio(1, 3), metre>>, foot>);
static_assert(std::is_same_v<downcast<scaled_unit<kilometre::ratio / hour::ratio, metre_per_second>>, kilometre_per_hour>);
static_assert(centimetre::symbol == "cm");
static_assert(kilometre::symbol == "km");