// 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 "test_tools.h" #include #include #include #include #include #ifdef MP_UNITS_IMPORT_STD import std; #else #include #include #include #include #include #if MP_UNITS_HOSTED #include #endif #endif namespace { using namespace mp_units; using namespace mp_units::si::unit_symbols; using namespace mp_units::usc::unit_symbols; #if MP_UNITS_HOSTED using namespace std::chrono_literals; using sys_seconds = std::chrono::time_point; #endif inline constexpr struct zeroth_length final : absolute_point_origin { } zeroth_length; inline constexpr struct mean_sea_level final : absolute_point_origin { } mean_sea_level; inline constexpr auto my_mean_sea_level = mean_sea_level; inline constexpr struct same_mean_sea_level final : relative_point_origin { } same_mean_sea_level; inline constexpr struct ground_level final : relative_point_origin { } ground_level; inline constexpr auto my_ground_level = ground_level; inline constexpr struct same_ground_level1 final : relative_point_origin { } same_ground_level1; inline constexpr struct same_ground_level2 final : relative_point_origin { } same_ground_level2; inline constexpr struct tower_peak final : relative_point_origin { } tower_peak; inline constexpr struct other_ground_level final : relative_point_origin { } other_ground_level; inline constexpr struct other_absolute_level final : absolute_point_origin { } other_absolute_level; inline constexpr struct zero final : absolute_point_origin { } zero; QUANTITY_SPEC(special_height, isq::height); ////////////////// // point origins ////////////////// static_assert(si::absolute_zero == si::zeroth_kelvin); static_assert(si::ice_point == si::zeroth_degree_Celsius); static_assert(si::absolute_zero != si::ice_point); static_assert(si::zeroth_kelvin != si::zeroth_degree_Celsius); static_assert(my_mean_sea_level == mean_sea_level); static_assert(my_mean_sea_level == same_mean_sea_level); static_assert(my_ground_level == ground_level); static_assert(same_ground_level1 == ground_level); static_assert(same_ground_level2 == my_ground_level); static_assert(mean_sea_level != zeroth_length); static_assert(mean_sea_level != other_absolute_level); static_assert(my_mean_sea_level != other_absolute_level); static_assert(ground_level != other_ground_level); template struct absolute_po_ final : absolute_point_origin {}; template constexpr absolute_po_ absolute_po; template struct relative_po_ final : relative_point_origin {}; template constexpr relative_po_ relative_po; static_assert(relative_po + isq::height(42 * m)>._quantity_spec_ == isq::height); static_assert(relative_po> + isq::height(42 * m)>._quantity_spec_ == isq::height); static_assert(relative_po + 42 * m>._quantity_spec_ == isq::height); inline constexpr struct my_kelvin final : named_unit<"my_K", mag<10> * si::kelvin> { } my_kelvin; static_assert(default_point_origin(si::kelvin) == si::absolute_zero); static_assert(default_point_origin(si::milli) == si::absolute_zero); static_assert(default_point_origin(mag<10> * si::kelvin) == si::absolute_zero); static_assert(default_point_origin(my_kelvin) == si::absolute_zero); static_assert(default_point_origin(si::degree_Celsius) == si::ice_point); static_assert(default_point_origin(mag<10> * si::degree_Celsius) == si::ice_point); static_assert(default_point_origin(si::metre) == zeroth_point_origin>); static_assert(default_point_origin(si::kelvin / si::second) == zeroth_point_origin>); static_assert(default_point_origin(si::degree_Celsius / si::second) == zeroth_point_origin>); static_assert(zeroth_point_origin == zeroth_point_origin); static_assert(zeroth_point_origin == zeroth_point_origin); static_assert(zeroth_point_origin> == zeroth_point_origin); static_assert(zeroth_point_origin> == zeroth_point_origin); static_assert(zeroth_point_origin != zeroth_point_origin); static_assert(zeroth_point_origin != zeroth_point_origin); static_assert(zeroth_point_origin != zeroth_point_origin); ///////////////////// // class invariants ///////////////////// static_assert(sizeof(quantity_point) == sizeof(double)); static_assert(sizeof(quantity_point) == sizeof(double)); static_assert(sizeof(quantity_point) == sizeof(short)); static_assert(sizeof(quantity_point) == sizeof(short)); template typename QP> concept invalid_types = requires { // unit of a different dimension requires !requires { typename QP; }; requires !requires { typename QP; }; // incompatible quantity_spec in the origin and quantity_point requires !requires { typename QP; }; requires !requires { typename QP; }; requires !requires { typename QP; }; requires !requires { typename QP; }; requires !requires { typename QP, int>; }; requires !requires { typename QP, int>; }; // quantity used as Rep requires !requires { typename QP>; }; // quantity point used as Rep requires !requires { typename QP>; }; // reordered arguments requires !requires { typename QP; }; // quantity_spec used as origin requires !requires { typename QP; }; // quantity_spec used as a reference requires !requires { typename QP; }; // dimension used as a reference requires !requires { typename QP; }; // bool used as a representation type requires !requires { typename QP; }; }; static_assert(invalid_types); template typename QP> concept valid_types = requires { typename QP; typename QP; typename QP; typename QP; typename QP; typename QP; typename QP, int>; typename QP>, int>; typename QP, int>; }; static_assert(valid_types); static_assert(std::is_trivially_default_constructible_v>); static_assert(std::is_trivially_copy_constructible_v>); static_assert(std::is_trivially_move_constructible_v>); static_assert(std::is_trivially_copy_assignable_v>); static_assert(std::is_trivially_move_assignable_v>); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_nothrow_default_constructible_v>); static_assert(std::is_nothrow_copy_constructible_v>); static_assert(std::is_nothrow_move_constructible_v>); static_assert(std::is_nothrow_copy_assignable_v>); static_assert(std::is_nothrow_move_assignable_v>); static_assert(std::is_nothrow_destructible_v>); static_assert(std::is_trivially_copyable_v>); static_assert(std::is_standard_layout_v>); static_assert(std::default_initializable>); static_assert(std::move_constructible>); static_assert(std::copy_constructible>); static_assert(std::equality_comparable>); static_assert(std::totally_ordered>); static_assert(std::regular>); static_assert(std::three_way_comparable>); ////////////////// // member values ////////////////// static_assert(quantity_point::reference == si::metre); static_assert(quantity_point::quantity_spec == kind_of); static_assert(quantity_point::dimension == isq::dim_length); static_assert(quantity_point::unit == si::metre); static_assert(is_of_type::point_origin, zeroth_point_origin_>>); static_assert(is_of_type::absolute_point_origin, zeroth_point_origin_>>); static_assert(quantity_point::reference == isq::height[m]); static_assert(quantity_point::quantity_spec == isq::height); static_assert(quantity_point::dimension == isq::dim_length); static_assert(quantity_point::unit == si::metre); static_assert(is_of_type::point_origin, zeroth_point_origin_>); static_assert(is_of_type::absolute_point_origin, zeroth_point_origin_>); static_assert(quantity_point::reference == si::metre); static_assert(quantity_point::quantity_spec == kind_of); static_assert(quantity_point::dimension == isq::dim_length); static_assert(quantity_point::unit == si::metre); static_assert(is_of_type::point_origin, struct mean_sea_level>); static_assert(is_of_type::absolute_point_origin, struct mean_sea_level>); static_assert(quantity_point::reference == isq::height[m]); static_assert(quantity_point::quantity_spec == isq::height); static_assert(quantity_point::dimension == isq::dim_length); static_assert(quantity_point::unit == si::metre); static_assert(is_of_type::point_origin, struct mean_sea_level>); static_assert(is_of_type::absolute_point_origin, struct mean_sea_level>); static_assert(quantity_point::reference == isq::height[m]); static_assert(quantity_point::quantity_spec == isq::height); static_assert(quantity_point::dimension == isq::dim_length); static_assert(quantity_point::unit == si::metre); static_assert(is_of_type::point_origin, struct ground_level>); static_assert(is_of_type::absolute_point_origin, struct mean_sea_level>); static_assert(quantity_point::reference == isq::height[m]); static_assert(quantity_point::quantity_spec == isq::height); static_assert(quantity_point::dimension == isq::dim_length); static_assert(quantity_point::unit == si::metre); static_assert(is_of_type::point_origin, struct tower_peak>); static_assert(is_of_type::absolute_point_origin, struct mean_sea_level>); static_assert(quantity_point::reference == si::kelvin); static_assert(quantity_point::quantity_spec == kind_of); static_assert(quantity_point::dimension == isq::dim_thermodynamic_temperature); static_assert(quantity_point::unit == si::kelvin); static_assert(is_of_type::point_origin, struct si::absolute_zero>); static_assert( is_of_type::absolute_point_origin, struct si::absolute_zero>); static_assert(quantity_point::reference == isq::thermodynamic_temperature[si::kelvin]); static_assert(quantity_point::quantity_spec == isq::thermodynamic_temperature); static_assert(quantity_point::dimension == isq::dim_thermodynamic_temperature); static_assert(quantity_point::unit == si::kelvin); static_assert(is_of_type::point_origin, struct si::absolute_zero>); static_assert( is_of_type::absolute_point_origin, struct si::absolute_zero>); static_assert(quantity_point::reference == isq::Celsius_temperature[si::kelvin]); static_assert(quantity_point::quantity_spec == isq::Celsius_temperature); static_assert(quantity_point::dimension == isq::dim_thermodynamic_temperature); static_assert(quantity_point::unit == si::kelvin); static_assert(is_of_type::point_origin, struct si::absolute_zero>); static_assert(is_of_type::absolute_point_origin, struct si::absolute_zero>); static_assert(quantity_point::reference == si::degree_Celsius); static_assert(quantity_point::quantity_spec == kind_of); static_assert(quantity_point::dimension == isq::dim_thermodynamic_temperature); static_assert(quantity_point::unit == si::degree_Celsius); static_assert(is_of_type::point_origin, struct si::ice_point>); static_assert( is_of_type::absolute_point_origin, struct si::absolute_zero>); static_assert(quantity_point::reference == isq::Celsius_temperature[si::degree_Celsius]); static_assert(quantity_point::quantity_spec == isq::Celsius_temperature); static_assert(quantity_point::dimension == isq::dim_thermodynamic_temperature); static_assert(quantity_point::unit == si::degree_Celsius); static_assert(is_of_type::point_origin, struct si::ice_point>); static_assert( is_of_type::absolute_point_origin, struct si::absolute_zero>); ////////////////// // member types ////////////////// static_assert(is_same_v::rep, double>); static_assert(is_same_v::quantity_type, quantity>); static_assert(is_same_v::rep, int>); static_assert(is_same_v::quantity_type, quantity>); static_assert(is_same_v::rep, double>); static_assert(is_same_v::quantity_type, quantity>); static_assert(is_same_v::rep, int>); static_assert( is_same_v::quantity_type, quantity>); //////////////////////////// // static member functions //////////////////////////// static_assert( quantity_point::min().quantity_from(mean_sea_level).numerical_value_in(m) == std::numeric_limits::lowest()); static_assert( quantity_point::max().quantity_from(mean_sea_level).numerical_value_in(m) == std::numeric_limits::max()); static_assert( quantity_point::min().quantity_from(ground_level).numerical_value_in(m) == std::numeric_limits::lowest()); static_assert( quantity_point::max().quantity_from(ground_level).numerical_value_in(m) == std::numeric_limits::max()); ////////////////////////////// // construction from a value ////////////////////////////// // there is no construction from a value static_assert(!std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, int>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, int>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, int>); static_assert(!std::convertible_to>); ///////////////////////////////// // construction from a quantity ///////////////////////////////// // ----------------------------- // implicit zeroth point origins // ----------------------------- static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // different dimensions static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // convertible but different quantity_specs static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // quantity_specs with get_common_quantity_spec static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // non-convertible quantity_specs static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); #if MP_UNITS_HOSTED // quantity-like static_assert(!std::constructible_from, std::chrono::seconds>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, std::chrono::seconds>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, std::chrono::seconds>); static_assert(!std::convertible_to>); #endif // ---------------------- // explicit point origins // ---------------------- static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // quantity_specs with get_common_quantity_spec static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // different dimensions static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // non-convertible quantity_specs static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); // not-compatible origin static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); #if MP_UNITS_HOSTED // quantity-like static_assert(!std::constructible_from>, std::chrono::seconds>); static_assert(!std::convertible_to>>); static_assert(!std::constructible_from>, std::chrono::seconds>); static_assert(!std::convertible_to>>); static_assert( !std::constructible_from>, std::chrono::seconds>); static_assert( !std::convertible_to>>); #endif /////////////////////////////////////// // construction from a quantity point /////////////////////////////////////// // implicit origin static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); // convertible but different quantity_specs static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // quantity_specs with get_common_quantity_spec static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // non-convertible quantity_specs static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // mixed origins static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // same explicit origins static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); // quantity_specs with get_common_quantity_spec static_assert(!std::constructible_from, quantity_point>); static_assert( !std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert( !std::convertible_to, quantity_point>); // different dimensions static_assert( !std::constructible_from, quantity_point>); static_assert( !std::convertible_to, quantity_point>); // non-convertible quantity_specs static_assert(std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // implicit conversion from another quantity point only if non-truncating // int -> double OK static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); // truncating double -> int not allowed static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // kilometre -> metre OK static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); // truncating metre -> kilometre not allowed static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // converting to double always OK static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); // same but not a default origin static_assert(std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert( std::constructible_from, quantity_point>); static_assert( std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(std::convertible_to, quantity_point>); static_assert(std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); // different origins static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); static_assert(!std::constructible_from, quantity_point>); static_assert(!std::convertible_to, quantity_point>); #if MP_UNITS_HOSTED // quantity-point-like static_assert( std::constructible_from>, sys_seconds>); static_assert( std::convertible_to>>); // incompatible origin static_assert( !std::constructible_from>, sys_seconds>); static_assert( !std::convertible_to>>); #endif ////////////////////////////////// // obtaining a relative quantity ////////////////////////////////// static_assert(quantity_point{42 * m}.quantity_from_zero() == 42 * m); static_assert(quantity_point{isq::height(42 * m)}.quantity_from_zero() == 42 * m); static_assert(quantity_point{delta(20)}.quantity_from_zero() == delta(20)); static_assert(quantity_point{delta(20.)}.in(deg_F).quantity_from_zero() == delta(68)); static_assert(point(20).quantity_from_zero() == delta(20)); static_assert(point(20.).in(deg_F).quantity_from_zero() == delta(68)); static_assert((mean_sea_level + 42 * m).quantity_from_zero() == 42 * m); static_assert((ground_level + 42 * m).quantity_from_zero() == 84 * m); static_assert((tower_peak + 42 * m).quantity_from_zero() == 126 * m); static_assert((mean_sea_level + 42 * m).quantity_from(mean_sea_level) == 42 * m); static_assert((mean_sea_level + isq::height(42 * m)).quantity_from(mean_sea_level) == 42 * m); static_assert((zero + 1 * one).quantity_from(zero) == 1 * one); static_assert((zero + dimensionless(1 * one)).quantity_from(zero) == 1 * one); static_assert((mean_sea_level + 42 * m).quantity_from(mean_sea_level) == 42 * m); static_assert((ground_level + 42 * m).quantity_from(ground_level) == 42 * m); static_assert((tower_peak + 42 * m).quantity_from(tower_peak) == 42 * m); static_assert(quantity_point(ground_level + 42 * m).quantity_from(mean_sea_level) == 84 * m); static_assert(quantity_point(tower_peak + 42 * m).quantity_from(mean_sea_level) == 126 * m); static_assert(quantity_point(mean_sea_level + 84 * m).quantity_from(ground_level) == 42 * m); static_assert(quantity_point(tower_peak + 42 * m).quantity_from(ground_level) == 84 * m); static_assert(quantity_point(mean_sea_level + 42 * m).quantity_from(tower_peak) == -42 * m); static_assert(quantity_point(ground_level + 84 * m).quantity_from(tower_peak) == 42 * m); static_assert((mean_sea_level + 42 * m).point_for(mean_sea_level).quantity_from(mean_sea_level) == 42 * m); static_assert((ground_level + 42 * m).point_for(mean_sea_level).quantity_from(mean_sea_level) == 84 * m); static_assert((tower_peak + 42 * m).point_for(mean_sea_level).quantity_from(mean_sea_level) == 126 * m); static_assert((ground_level + 84 * m).point_for(ground_level).quantity_from(ground_level) == 84 * m); static_assert((mean_sea_level + 84 * m).point_for(ground_level).quantity_from(ground_level) == 42 * m); static_assert((tower_peak + 42 * m).point_for(ground_level).quantity_from(ground_level) == 84 * m); static_assert((tower_peak + 42 * m).point_for(tower_peak).quantity_from(tower_peak) == 42 * m); static_assert((mean_sea_level + 42 * m).point_for(tower_peak).quantity_from(tower_peak) == -42 * m); static_assert((ground_level + 84 * m).point_for(tower_peak).quantity_from(tower_peak) == 42 * m); static_assert(is_of_type<(ground_level + isq::height(short{42} * m)).point_for(mean_sea_level), quantity_point>); /////////////////////////////////// // converting to a different unit /////////////////////////////////// static_assert((mean_sea_level + 2. * km).in(km).quantity_from(mean_sea_level).numerical_value_in(km) == 2.); static_assert((mean_sea_level + 2. * km).in(m).quantity_from(mean_sea_level).numerical_value_in(m) == 2000.); static_assert((mean_sea_level + 2000. * m).in(km).quantity_from(mean_sea_level).numerical_value_in(km) == 2.); static_assert((ground_level + 2. * km).in(km).quantity_from(ground_level).numerical_value_in(km) == 2.); static_assert((ground_level + 2. * km).in(m).quantity_from(ground_level).numerical_value_in(m) == 2000.); static_assert((ground_level + 2000. * m).in(km).quantity_from(ground_level).numerical_value_in(km) == 2.); static_assert((tower_peak + 2. * km).in(km).quantity_from(tower_peak).numerical_value_in(km) == 2.); static_assert((tower_peak + 2. * km).in(m).quantity_from(tower_peak).numerical_value_in(m) == 2000.); static_assert((tower_peak + 2000. * m).in(km).quantity_from(tower_peak).numerical_value_in(km) == 2.); static_assert(is_of_type<(mean_sea_level + 2 * km).in(m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 2 * km).in(), quantity_point>); static_assert(is_of_type<(mean_sea_level + 2 * km).in(m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 2500. * m).force_in(km), quantity_point>); static_assert(is_of_type<(mean_sea_level + 2500. * m).force_in(), quantity_point>); static_assert(is_of_type<(mean_sea_level + 2500. * m).force_in(km), quantity_point>); template typename QP> concept invalid_unit_conversion = requires { requires !requires { QP(2000 * m).in(km); }; // truncating conversion requires !requires { QP(2 * m).in(s); }; // invalid unit }; static_assert(invalid_unit_conversion); ///////// // CTAD ///////// static_assert(std::is_same_v); static_assert(std::is_same_v>>); static_assert(std::is_same_v>>); static_assert(quantity_point{123 * m}.unit == si::metre); static_assert(quantity_point{123 * m}.quantity_spec == kind_of); static_assert(std::is_same_v); static_assert(std::is_same_v, zeroth_point_origin_>); static_assert(std::is_same_v, zeroth_point_origin_>); static_assert(quantity_point{isq::height(123 * m)}.unit == si::metre); static_assert(quantity_point{isq::height(123 * m)}.quantity_spec == isq::height); static_assert(std::is_same_v(20)})::rep, int>); static_assert( std::is_same_v(20)}.point_origin)>, struct si::ice_point>); static_assert(std::is_same_v(20)}.absolute_point_origin)>, struct si::absolute_zero>); static_assert(quantity_point{delta(20)}.unit == si::degree_Celsius); static_assert(quantity_point{delta(20)}.quantity_spec == kind_of); #if MP_UNITS_HOSTED using namespace std::chrono_literals; static_assert(std::is_same_v); static_assert(std::is_same_v>); static_assert(std::is_same_v>); static_assert(quantity_point{sys_seconds{24h}}.unit == si::second); static_assert(quantity_point{sys_seconds{24h}}.quantity_spec == kind_of); #endif //////////// // getters //////////// constexpr quantity_point mean_sea_level_qp = mean_sea_level + 1 * m; constexpr quantity_point my_mean_sea_level_qp = my_mean_sea_level + 1 * m; constexpr quantity_point ground_level_qp = ground_level + 1 * m; constexpr quantity_point my_ground_level_qp = my_ground_level + 1 * m; constexpr quantity_point same_ground_level1_qp = same_ground_level1 + 1 * m; constexpr quantity_point same_ground_level2_qp = same_ground_level2 + 1 * m; static_assert(mean_sea_level_qp.quantity_ref_from(mean_sea_level) == 1 * m); static_assert(mean_sea_level_qp.quantity_ref_from(my_mean_sea_level) == 1 * m); static_assert(my_mean_sea_level_qp.quantity_ref_from(my_mean_sea_level) == 1 * m); static_assert(my_mean_sea_level_qp.quantity_ref_from(mean_sea_level) == 1 * m); static_assert(ground_level_qp.quantity_ref_from(ground_level) == 1 * m); static_assert(ground_level_qp.quantity_ref_from(my_ground_level) == 1 * m); static_assert(ground_level_qp.quantity_ref_from(same_ground_level1) == 1 * m); static_assert(ground_level_qp.quantity_ref_from(same_ground_level2) == 1 * m); static_assert(my_ground_level_qp.quantity_ref_from(my_ground_level) == 1 * m); static_assert(my_ground_level_qp.quantity_ref_from(ground_level) == 1 * m); static_assert(my_ground_level_qp.quantity_ref_from(same_ground_level1) == 1 * m); static_assert(my_ground_level_qp.quantity_ref_from(same_ground_level2) == 1 * m); static_assert(same_ground_level1_qp.quantity_ref_from(my_ground_level) == 1 * m); static_assert(same_ground_level1_qp.quantity_ref_from(ground_level) == 1 * m); static_assert(same_ground_level1_qp.quantity_ref_from(same_ground_level1) == 1 * m); static_assert(same_ground_level1_qp.quantity_ref_from(same_ground_level2) == 1 * m); static_assert(same_ground_level2_qp.quantity_ref_from(my_ground_level) == 1 * m); static_assert(same_ground_level2_qp.quantity_ref_from(ground_level) == 1 * m); static_assert(same_ground_level2_qp.quantity_ref_from(same_ground_level1) == 1 * m); static_assert(same_ground_level2_qp.quantity_ref_from(same_ground_level2) == 1 * m); //////////////////////// // assignment operator //////////////////////// static_assert(([]() { const quantity_point l1{mean_sea_level + 1 * m}; quantity_point l2{mean_sea_level + 2 * m}; return l2 = l1; }()) .quantity_from(mean_sea_level) == 1 * m); static_assert(([]() { const quantity_point l1{mean_sea_level + 1 * m}; quantity_point l2{mean_sea_level + 2 * m}; return l2 = l1; }()) .quantity_from(mean_sea_level) == 1 * m); static_assert(([]() { quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m}; return l2 = std::move(l1); // NOLINT(*-move-const-arg) }()) .quantity_from(mean_sea_level) == 1 * m); //////////////////// // unary operators //////////////////// static_assert([](auto v) { auto vv = v++; // NOLINT(bugprone-inc-dec-in-conditions) return std::pair(v, vv); }(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 124 * m, quantity_point(mean_sea_level + 123 * m))); static_assert([](auto v) { auto vv = ++v; // NOLINT(bugprone-inc-dec-in-conditions) return std::pair(v, vv); }(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 124 * m, mean_sea_level + 124 * m)); static_assert([](auto v) { auto vv = v--; // NOLINT(bugprone-inc-dec-in-conditions) return std::pair(v, vv); }(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 122 * m, mean_sea_level + 123 * m)); static_assert([](auto v) { auto vv = --v; // NOLINT(bugprone-inc-dec-in-conditions) return std::pair(v, vv); }(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 122 * m, mean_sea_level + 122 * m)); //////////////////////// // compound assignment //////////////////////// // same type static_assert( [qp = mean_sea_level + 1 * m]() mutable { return qp += 1 * m; }().quantity_from_zero().numerical_value_in(m) == 2); static_assert( [qp = mean_sea_level + 2 * m]() mutable { return qp -= 1 * m; }().quantity_from_zero().numerical_value_in(m) == 1); // different types static_assert( [qp = mean_sea_level + 2.5 * m]() mutable { return qp += 3 * m; }().quantity_from_zero().numerical_value_in(m) == 5.5); static_assert( [qp = mean_sea_level + 123 * m]() mutable { return qp += 1 * km; }().quantity_from_zero().numerical_value_in(m) == 1123); static_assert( [qp = mean_sea_level + 5.5 * m]() mutable { return qp -= 3 * m; }().quantity_from_zero().numerical_value_in(m) == 2.5); static_assert( [qp = mean_sea_level + 1123 * m]() mutable { return qp -= 1 * km; }().quantity_from_zero().numerical_value_in(m) == 123); template typename QP> concept invalid_compound_assignments = requires() { // truncating not allowed requires !requires(QP l) { l += 2.5 * m; }; requires !requires(QP l) { l -= 2.5 * m; }; requires !requires(QP l) { l += 2 * isq::height[m]; }; requires !requires(QP l) { l -= 2 * isq::height[m]; }; // only quantities can be added or subtracted requires !requires(QP l) { l += 2; }; requires !requires(QP l) { l -= 2; }; // no unit constants requires !requires(QP l) { l += m; }; requires !requires(QP l) { l -= m; }; }; static_assert(invalid_compound_assignments); //////////////////// // binary operators //////////////////// template typename QP, auto Origin, auto OtherOrigin> concept invalid_binary_operations = requires { // can't add two quantity points requires !requires { QP(1 * m) + QP(1 * m); }; requires !requires { mean_sea_level + QP(1 * m); }; requires !requires { QP(1 * m) + mean_sea_level; }; requires !requires { Origin + Origin; }; // can't add more generic quantity (violates point_origin quantity_spec) requires !requires { QP(1 * m) + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + QP(1 * m); }; requires !requires { QP(1 * m) + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + QP(1 * m); }; requires !requires { QP, int>(1 * m) + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + QP, int>(1 * m); }; requires !requires { QP, int>(1 * m) + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + QP, int>(1 * m); }; requires !requires { Origin + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + Origin; }; // can't subtract more generic quantity (violates point_origin quantity_spec) requires !requires { QP(1 * m) - isq::length(1 * m); }; requires !requires { QP(1 * m) - isq::length(1 * m); }; requires !requires { QP, int>(1 * m) - isq::length(1 * m); }; requires !requires { QP, int>(1 * m) - isq::length(1 * m); }; requires !requires { QP, int>(10 * isq::height[m] / (2 * isq::time[s])) + 5 * isq::speed[m / s]; }; requires !requires { 5 * isq::speed[m / s] + QP, int>( 10 * isq::height[m] / (2 * isq::time[s])); }; requires !requires { QP, int>(10 * isq::height[m] / (2 * isq::time[s])) - 5 * isq::speed[m / s]; }; requires !requires { Origin - isq::length(1 * m); }; // quantity point can't be subtracted from a quantity requires !requires { 1 * m - QP(1 * m); }; requires !requires { 1 * m - Origin; }; // no crossdimensional addition and subtraction requires !requires { QP(1 * m) + 1 * s; }; requires !requires { QP(1 * m) - 1 * s; }; requires !requires { Origin + 1 * s; }; requires !requires { Origin - 1 * s; }; // can't subtract two quantity points of incompatible origins requires !requires { QP(1 * m) - QP(1 * m); }; requires !requires { QP(1 * m) - QP(1 * m); }; requires !requires { mean_sea_level - QP(1 * m); }; requires !requires { QP(1 * m) - other_absolute_level; }; requires !requires { QP(1 * m) - quantity_point{1 * m}; }; requires !requires { quantity_point{1 * m} - QP(1 * m); }; requires !requires { QP, int>(1 * m) - quantity_point{isq::height(1 * m)}; }; requires !requires { quantity_point{isq::height(1 * m)} - QP, int>(1 * m); }; requires !requires { QP, int>(1 * m) - quantity_point{isq::length(1 * m)}; }; requires !requires { quantity_point{isq::length(1 * m)} - QP, int>(1 * m); }; requires !requires { quantity_point{10 * isq::height[m] / (2 * isq::time[s])} - QP, int>(5 * isq::speed[m / s]); }; requires !requires { QP, int>(5 * isq::speed[m / s]) - quantity_point{10 * isq::height[m] / (2 * isq::time[s])}; }; // cant'subtract two unrelated points requires !requires { Origin - OtherOrigin; }; // cant'subtract the same point as we do not know the unit for the resulting quantity requires !requires { Origin - Origin; }; // unit constants requires !requires { QP(1) + m; }; requires !requires { QP(1) - m; }; requires !requires { Origin + m; }; requires !requires { Origin - m; }; requires !requires { m + QP(1); }; requires !requires { m - QP(1); }; requires !requires { m + Origin; }; requires !requires { m - Origin; }; }; static_assert(invalid_binary_operations); // same representation type static_assert(is_of_type<(mean_sea_level + 1 * m) + 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) + 1 * km, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) + 1 * m, quantity_point>); static_assert( is_of_type<(mean_sea_level + 1 * m) + isq::height(1 * m), quantity_point>); static_assert( is_of_type<(mean_sea_level + 1 * m) + isq::height(1 * km), quantity_point>); static_assert( is_of_type<(mean_sea_level + 1 * km) + isq::height(1 * m), quantity_point>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * m)) + 1 * m, quantity_point>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * m)) + 1 * km, quantity_point>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * km)) + 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) + isq::height(1 * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) + isq::height(1 * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * km)) + isq::height(1 * m), quantity_point>); static_assert(is_of_type<1 * m + (mean_sea_level + 1 * m), quantity_point>); static_assert(is_of_type<1 * m + (mean_sea_level + 1 * km), quantity_point>); static_assert(is_of_type<1 * km + (mean_sea_level + 1 * m), quantity_point>); static_assert( is_of_type<1 * m + (mean_sea_level + isq::height(1 * m)), quantity_point>); static_assert( is_of_type<1 * m + (mean_sea_level + isq::height(1 * km)), quantity_point>); static_assert( is_of_type<1 * km + (mean_sea_level + isq::height(1 * m)), quantity_point>); static_assert( is_of_type>); static_assert( is_of_type>); static_assert( is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type, mean_sea_level, int>>); static_assert(is_of_type>); static_assert( is_of_type>); static_assert(is_of_type], mean_sea_level, int>>); static_assert(is_of_type<1 * m + mean_sea_level, quantity_point>); static_assert(is_of_type<1 * km + mean_sea_level, quantity_point, mean_sea_level, int>>); static_assert(is_of_type>); static_assert( is_of_type>); static_assert(is_of_type], mean_sea_level, int>>); static_assert(is_of_type>); static_assert(is_of_type, ground_level, int>>); static_assert(is_of_type<1 * m + ground_level, quantity_point>); static_assert(is_of_type<1 * km + ground_level, quantity_point, ground_level, int>>); static_assert(is_of_type<(mean_sea_level + 1 * m) - 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) - 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) - 1 * km, quantity_point>); static_assert( is_of_type<(mean_sea_level + 1 * m) - isq::height(1 * m), quantity_point>); static_assert( is_of_type<(mean_sea_level + 1 * m) - isq::height(1 * km), quantity_point>); static_assert( is_of_type<(mean_sea_level + 1 * km) - isq::height(1 * m), quantity_point>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * m)) - 1 * m, quantity_point>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * m)) - 1 * km, quantity_point>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * km)) - 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - isq::height(1 * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - isq::height(1 * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * km)) - isq::height(1 * m), quantity_point>); static_assert(is_of_type>); static_assert(is_of_type, mean_sea_level, int>>); static_assert( is_of_type>); static_assert(is_of_type], mean_sea_level, int>>); static_assert(is_of_type>); static_assert(is_of_type, ground_level, int>>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * km), quantity>); static_assert( is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + isq::height(1 * m)), quantity>); static_assert( is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + isq::height(1 * km)), quantity>); static_assert( is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + isq::height(1 * m)), quantity>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + 1 * m), quantity>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + 1 * km), quantity>); static_assert( is_of_type<(mean_sea_level + isq::height(1 * km)) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + isq::height(1 * m)), quantity>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + isq::height(1 * km)), quantity>); static_assert(is_of_type<(mean_sea_level + isq::height(1 * km)) - (mean_sea_level + isq::height(1 * m)), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(ground_level + 1 * m) - (ground_level + 1 * m), quantity>); static_assert(is_of_type<(tower_peak + 1 * m) - (tower_peak + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (ground_level + 1 * m), quantity>); static_assert(is_of_type<(ground_level + 1 * m) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(tower_peak + 1 * m) - (ground_level + 1 * m), quantity>); static_assert(is_of_type<(ground_level + 1 * m) - (tower_peak + 1 * m), quantity>); static_assert(is_of_type<(tower_peak + 1 * m) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (tower_peak + 1 * m), quantity>); static_assert(is_of_type<(other_ground_level + 1 * m) - (ground_level + 1 * m), quantity>); static_assert(is_of_type<(ground_level + 1 * m) - (other_ground_level + 1 * m), quantity>); static_assert(is_of_type<(other_ground_level + 1 * m) - (tower_peak + 1 * m), quantity>); static_assert(is_of_type<(tower_peak + 1 * m) - (other_ground_level + 1 * m), quantity>); static_assert(is_of_type>); static_assert(is_of_type, int>>); static_assert(is_of_type<(mean_sea_level + 1 * m) - mean_sea_level, quantity>); static_assert(is_of_type<(mean_sea_level + 1 * km) - mean_sea_level, quantity, int>>); static_assert(is_of_type>); static_assert(is_of_type, int>>); static_assert(is_of_type<(ground_level + 1 * m) - ground_level, quantity>); static_assert(is_of_type<(ground_level + 1 * km) - ground_level, quantity, int>>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type<(ground_level + 1 * m) - mean_sea_level, quantity>); static_assert(is_of_type<(ground_level + 1 * km) - mean_sea_level, quantity>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type<(mean_sea_level + 1 * m) - ground_level, quantity>); static_assert(is_of_type<(mean_sea_level + 1 * km) - ground_level, quantity>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type<(1 * m + mean_sea_level) - (1 * m + ground_level), quantity>); static_assert(is_of_type<(1 * m + ground_level) - (1 * m + mean_sea_level), quantity>); static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + ground_level), quantity>); static_assert(is_of_type<(1 * m + ground_level) - (1 * m + tower_peak), quantity>); static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + mean_sea_level), quantity>); static_assert(is_of_type<(1 * m + mean_sea_level) - (1 * m + tower_peak), quantity>); static_assert(is_of_type<(1 * m + other_ground_level) - (1 * m + ground_level), quantity>); static_assert(is_of_type<(1 * m + ground_level) - (1 * m + other_ground_level), quantity>); static_assert(is_of_type<(1 * m + other_ground_level) - (1 * m + tower_peak), quantity>); static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), quantity>); // check for integral types promotion static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(((mean_sea_level + std::uint8_t{128} * m) + std::uint8_t{128} * m) .quantity_from(mean_sea_level) .numerical_value_in(m) == std::uint8_t{128} + std::uint8_t{128}); static_assert((std::uint8_t{128} * m + (mean_sea_level + std::uint8_t{128} * m)) .quantity_from(mean_sea_level) .numerical_value_in(m) == std::uint8_t{128} + std::uint8_t{128}); static_assert( ((mean_sea_level + std::uint8_t{0} * m) - std::uint8_t{1} * m).quantity_from(mean_sea_level).numerical_value_in(m) == std::uint8_t{0} - std::uint8_t{1}); static_assert(((mean_sea_level + std::uint8_t{0} * m) - (mean_sea_level + std::uint8_t{1} * m)).numerical_value_in(m) == std::uint8_t{0} - std::uint8_t{1}); // different representation types static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * m, quantity_point>); static_assert(is_of_type<1. * m + (mean_sea_level + 1 * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) + 1. * km, quantity_point>); static_assert(is_of_type<1 * m + (mean_sea_level + 1. * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) + 1. * m, quantity_point>); static_assert(is_of_type<1 * km + (mean_sea_level + 1. * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) - 1. * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * km) - 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * m) - 1 * km, quantity_point>); // different units static_assert(is_of_type<(mean_sea_level + 1 * m) + 1 * km, quantity_point>); static_assert(is_of_type<1 * m + (mean_sea_level + 1 * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * km, quantity_point>); static_assert(is_of_type<1. * m + (mean_sea_level + 1 * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) + 1. * km, quantity_point>); static_assert(is_of_type<1 * m + (mean_sea_level + 1. * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * m) + 1. * km, quantity_point>); static_assert(is_of_type<1. * m + (mean_sea_level + 1. * km), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) + 1 * m, quantity_point>); static_assert(is_of_type<1 * km + (mean_sea_level + 1 * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * km) + 1 * m, quantity_point>); static_assert(is_of_type<1. * km + (mean_sea_level + 1 * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) + 1. * m, quantity_point>); static_assert(is_of_type<1 * km + (mean_sea_level + 1. * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * km) + 1. * m, quantity_point>); static_assert(is_of_type<1. * km + (mean_sea_level + 1. * m), quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) - 1 * km, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * m) - 1 * km, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) - 1. * km, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * m) - 1. * km, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) - 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * km) - 1 * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * km) - 1. * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1. * km) - 1. * m, quantity_point>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * km), quantity>); static_assert(is_of_type<(mean_sea_level + 1. * m) - (mean_sea_level + 1 * km), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1. * km), quantity>); static_assert(is_of_type<(mean_sea_level + 1. * m) - (mean_sea_level + 1. * km), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1 * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m), quantity>); static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity>); static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 2); static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from(mean_sea_level).numerical_value_in(m) == 2); static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from(mean_sea_level).numerical_value_in(m) == 1001); static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from(mean_sea_level).numerical_value_in(m) == 1001); static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 1001); static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from(mean_sea_level).numerical_value_in(m) == 1001); static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 1); static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 999); static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 2.5); static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from(mean_sea_level).numerical_value_in(m) == 2.5); static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from(mean_sea_level).numerical_value_in(m) == 1001.5); static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from(mean_sea_level).numerical_value_in(m) == 1001.5); static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 1501); static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from(mean_sea_level).numerical_value_in(m) == 1501); static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 1.5); static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 1499); static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 2.5); static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from(mean_sea_level).numerical_value_in(m) == 2.5); static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from(mean_sea_level).numerical_value_in(m) == 1501); static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from(mean_sea_level).numerical_value_in(m) == 1501); static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 1001.5); static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from(mean_sea_level).numerical_value_in(m) == 1001.5); static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 0.5); static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from(mean_sea_level).numerical_value_in(m) == 998.5); static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 1); static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 999); static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 1.5); static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 1499); static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_in(m) == 0.5); static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_in(m) == 998.5); static_assert((mean_sea_level + 42 * m) - (ground_level + 42 * m) == -42 * m); static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m); static_assert((tower_peak + 42 * m) - (ground_level + 42 * m) == 42 * m); static_assert((ground_level + 42 * m) - (tower_peak + 42 * m) == -42 * m); static_assert((tower_peak + 42 * m) - (mean_sea_level + 42 * m) == 84 * m); static_assert((mean_sea_level + 42 * m) - (tower_peak + 42 * m) == -84 * m); static_assert((other_ground_level + 42 * m) - (ground_level + 42 * m) == 81 * m); static_assert((ground_level + 42 * m) - (other_ground_level + 42 * m) == -81 * m); static_assert((other_ground_level + 42 * m) - (tower_peak + 42 * m) == 39 * m); static_assert((tower_peak + 42 * m) - (other_ground_level + 42 * m) == -39 * m); static_assert((mean_sea_level + 42 * m).quantity_from(ground_level + 42 * m) == -42 * m); static_assert((ground_level + 42 * m).quantity_from(mean_sea_level + 42 * m) == 42 * m); static_assert((tower_peak + 42 * m).quantity_from(ground_level + 42 * m) == 42 * m); static_assert((ground_level + 42 * m).quantity_from(tower_peak + 42 * m) == -42 * m); static_assert((tower_peak + 42 * m).quantity_from(mean_sea_level + 42 * m) == 84 * m); static_assert((mean_sea_level + 42 * m).quantity_from(tower_peak + 42 * m) == -84 * m); static_assert((other_ground_level + 42 * m).quantity_from(ground_level + 42 * m) == 81 * m); static_assert((ground_level + 42 * m).quantity_from(other_ground_level + 42 * m) == -81 * m); static_assert((other_ground_level + 42 * m).quantity_from(tower_peak + 42 * m) == 39 * m); static_assert((tower_peak + 42 * m).quantity_from(other_ground_level + 42 * m) == -39 * m); static_assert((mean_sea_level + 42 * m).quantity_from(mean_sea_level) == 42 * m); static_assert((42 * m + mean_sea_level).quantity_from(mean_sea_level) == 42 * m); static_assert((mean_sea_level - 42 * m).quantity_from(mean_sea_level) == -42 * m); static_assert((ground_level + 42 * m).quantity_from(ground_level) == 42 * m); static_assert((42 * m + ground_level).quantity_from(ground_level) == 42 * m); static_assert((ground_level - 42 * m).quantity_from(ground_level) == -42 * m); static_assert((tower_peak + 42 * m).quantity_from(tower_peak) == 42 * m); static_assert((42 * m + tower_peak).quantity_from(tower_peak) == 42 * m); static_assert((tower_peak - 42 * m).quantity_from(tower_peak) == -42 * m); static_assert((mean_sea_level + 42 * m) - ground_level == 0 * m); static_assert((ground_level + 42 * m) - mean_sea_level == 84 * m); static_assert((tower_peak + 42 * m) - ground_level == 84 * m); static_assert((ground_level + 42 * m) - tower_peak == 0 * m); static_assert((tower_peak + 42 * m) - mean_sea_level == 126 * m); static_assert((mean_sea_level + 42 * m) - tower_peak == -42 * m); static_assert((other_ground_level + 42 * m) - ground_level == 123 * m); static_assert((ground_level + 42 * m) - other_ground_level == -39 * m); static_assert((other_ground_level + 42 * m) - tower_peak == 81 * m); static_assert((tower_peak + 42 * m) - other_ground_level == 3 * m); static_assert((mean_sea_level + 42 * m).quantity_from(ground_level) == 0 * m); static_assert((ground_level + 42 * m).quantity_from(mean_sea_level) == 84 * m); static_assert((tower_peak + 42 * m).quantity_from(ground_level) == 84 * m); static_assert((ground_level + 42 * m).quantity_from(tower_peak) == 0 * m); static_assert((tower_peak + 42 * m).quantity_from(mean_sea_level) == 126 * m); static_assert((mean_sea_level + 42 * m).quantity_from(tower_peak) == -42 * m); static_assert((other_ground_level + 42 * m).quantity_from(ground_level) == 123 * m); static_assert((ground_level + 42 * m).quantity_from(other_ground_level) == -39 * m); static_assert((other_ground_level + 42 * m).quantity_from(tower_peak) == 81 * m); static_assert((tower_peak + 42 * m).quantity_from(other_ground_level) == 3 * m); static_assert(mean_sea_level - (ground_level + 42 * m) == -84 * m); static_assert(ground_level - (mean_sea_level + 42 * m) == 0 * m); static_assert(tower_peak - (ground_level + 42 * m) == 0 * m); static_assert(ground_level - (tower_peak + 42 * m) == -84 * m); static_assert(tower_peak - (mean_sea_level + 42 * m) == 42 * m); static_assert(mean_sea_level - (tower_peak + 42 * m) == -126 * m); static_assert(other_ground_level - (ground_level + 42 * m) == 39 * m); static_assert(ground_level - (other_ground_level + 42 * m) == -123 * m); static_assert(other_ground_level - (tower_peak + 42 * m) == -3 * m); static_assert(tower_peak - (other_ground_level + 42 * m) == -81 * m); static_assert(mean_sea_level - ground_level == -42 * m); static_assert(ground_level - mean_sea_level == 42 * m); static_assert(tower_peak - ground_level == 42 * m); static_assert(ground_level - tower_peak == -42 * m); static_assert(tower_peak - mean_sea_level == 84 * m); static_assert(mean_sea_level - tower_peak == -84 * m); static_assert(other_ground_level - ground_level == 81 * m); static_assert(ground_level - other_ground_level == -81 * m); static_assert(other_ground_level - tower_peak == 39 * m); static_assert(tower_peak - other_ground_level == -39 * m); inline constexpr struct zero_m_per_s final : absolute_point_origin> { } zero_m_per_s; // commutativity and associativity static_assert(((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + 5 * isq::speed[m / s]) .quantity_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert((10 * isq::height[m] / (2 * isq::time[s]) + (zero_m_per_s + 5 * isq::speed[m / s])) .quantity_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert(((zero_m_per_s + 5 * isq::speed[m / s]) + 10 * isq::height[m] / (2 * isq::time[s])) .quantity_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert((5 * isq::speed[m / s] + (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s]))) .quantity_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert(((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - 5 * isq::speed[m / s]) .quantity_from(zero_m_per_s) == 0 * isq::speed[m / s]); static_assert(((zero_m_per_s + 5 * isq::speed[m / s]) - 10 * isq::height[m] / (2 * isq::time[s])) .quantity_from(zero_m_per_s) == 0 * isq::speed[m / s]); static_assert((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - (zero_m_per_s + 5 * isq::speed[m / s]) == 0 * isq::speed[m / s]); static_assert((zero_m_per_s + 5 * isq::speed[m / s]) - (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) == 0 * isq::speed[m / s]); static_assert(is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + 5 * isq::speed[m / s], quantity_point>); static_assert(is_of_type<10 * isq::height[m] / (2 * isq::time[s]) + (zero_m_per_s + 5 * isq::speed[m / s]), quantity_point>); static_assert(is_of_type<(zero_m_per_s + 5 * isq::speed[m / s]) + 10 * isq::height[m] / (2 * isq::time[s]), quantity_point>); static_assert(is_of_type<5 * isq::speed[m / s] + (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])), quantity_point>); static_assert(is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - 5 * isq::speed[m / s], quantity_point>); static_assert(is_of_type<(zero_m_per_s + 5 * isq::speed[m / s]) - 10 * isq::height[m] / (2 * isq::time[s]), quantity_point>); static_assert( is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - (zero_m_per_s + 5 * isq::speed[m / s]), quantity>); static_assert( is_of_type<(zero_m_per_s + 5 * isq::speed[m / s]) - (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])), quantity>); static_assert( is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + (10 * isq::height[m] / (2 * isq::time[s])), quantity_point<(isq::height / isq::time)[m / s], zero_m_per_s, int>>); static_assert((quantity_point{5 * isq::speed[m / s]} + 10 * isq::length[m] / (2 * isq::time[s])).quantity_from_zero() == 10 * isq::speed[m / s]); static_assert((10 * isq::length[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]}).quantity_from_zero() == 10 * isq::speed[m / s]); static_assert((quantity_point{5 * isq::speed[m / s]} - 10 * isq::length[m] / (2 * isq::time[s])).quantity_from_zero() == 0 * isq::speed[m / s]); static_assert((quantity_point{10 * isq::length[m] / (2 * isq::time[s])} + 5 * isq::speed[m / s]).quantity_from_zero() == 10 * isq::speed[m / s]); static_assert((5 * isq::speed[m / s] + quantity_point{10 * isq::length[m] / (2 * isq::time[s])}).quantity_from_zero() == 10 * isq::speed[m / s]); static_assert((quantity_point{10 * isq::length[m] / (2 * isq::time[s])} - 5 * isq::speed[m / s]).quantity_from_zero() == 0 * isq::speed[m / s]); static_assert((quantity_point{5 * isq::speed[m / s]} + 10 * isq::height[m] / (2 * isq::time[s])).quantity_from_zero() == 10 * isq::speed[m / s]); static_assert((10 * isq::height[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]}).quantity_from_zero() == 10 * isq::speed[m / s]); static_assert((quantity_point{5 * isq::speed[m / s]} - 10 * isq::height[m] / (2 * isq::time[s])).quantity_from_zero() == 0 * isq::speed[m / s]); static_assert(is_of_type, int>>); static_assert(is_of_type<10 * isq::height[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]}, quantity_point, int>>); static_assert(is_of_type, int>>); static_assert(is_of_type<5 * isq::speed[m / s] + quantity_point{10 * isq::length[m] / (2 * isq::time[s])}, quantity_point, int>>); static_assert(is_of_type, int>>); static_assert(is_of_type, int>>); static_assert( is_of_type>); static_assert( is_of_type>); static_assert( is_of_type, int>>); inline constexpr struct zero_Hz final : absolute_point_origin> { } zero_Hz; static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_from(zero_Hz) == 10 * isq::frequency[Hz]); static_assert((10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz])).quantity_from(zero_Hz) == 10 * isq::frequency[Hz]); static_assert(((zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s])).quantity_from(zero_Hz) == 10 * isq::frequency[Hz]); static_assert((5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s]))).quantity_from(zero_Hz) == 10 * isq::frequency[Hz]); static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz]).quantity_from(zero_Hz) == 0 * isq::frequency[Hz]); static_assert(((zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s])).quantity_from(zero_Hz) == 0 * isq::frequency[Hz]); static_assert((zero_Hz + 10 / (2 * isq::period_duration[s])) - (zero_Hz + 5 * isq::frequency[Hz]) == 0 * isq::frequency[Hz]); static_assert((zero_Hz + 5 * isq::frequency[Hz]) - (zero_Hz + 10 / (2 * isq::period_duration[s])) == 0 * isq::frequency[Hz]); static_assert(is_of_type<(zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz], quantity_point>); static_assert(is_of_type<10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz]), quantity_point>); static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s]), quantity_point>); static_assert(is_of_type<5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s])), quantity_point>); static_assert(is_of_type<(zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz], quantity_point>); static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s]), quantity_point>); static_assert(is_of_type<(zero_Hz + 10 / (2 * isq::period_duration[s])) - (zero_Hz + 5 * isq::frequency[Hz]), quantity>); static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) - (zero_Hz + 10 / (2 * isq::period_duration[s])), quantity>); static_assert((quantity_point{10 / (2 * isq::period_duration[s])} + 5 * isq::frequency[Hz]).quantity_from_zero() == 10 * isq::frequency[Hz]); static_assert((10 / (2 * isq::period_duration[s]) + quantity_point{zero_Hz + 5 * isq::frequency[Hz]}) .quantity_from_zero() == 10 * isq::frequency[Hz]); static_assert((quantity_point{5 * isq::frequency[Hz]} + 10 / (2 * isq::period_duration[s])).quantity_from_zero() == 10 * isq::frequency[Hz]); static_assert((5 * isq::frequency[Hz] + quantity_point{10 / (2 * isq::period_duration[s])}).quantity_from_zero() == 10 * isq::frequency[Hz]); static_assert((quantity_point{10 / (2 * isq::period_duration[s])} - 5 * isq::frequency[Hz]).quantity_from_zero() == 0 * isq::frequency[Hz]); static_assert((quantity_point{5 * isq::frequency[Hz]} - 10 / (2 * isq::period_duration[s])).quantity_from_zero() == 0 * isq::frequency[Hz]); static_assert(quantity_point{10 / (2 * isq::period_duration[s])} - quantity_point{5 * isq::frequency[Hz]} == 0 * isq::frequency[Hz]); static_assert(quantity_point{5 * isq::frequency[Hz]} - quantity_point{10 / (2 * isq::period_duration[s])} == 0 * isq::frequency[Hz]); static_assert(is_of_type, int>>); static_assert(is_of_type<10 / (2 * isq::period_duration[s]) + quantity_point{5 * isq::frequency[Hz]}, quantity_point, int>>); static_assert(is_of_type, int>>); static_assert(is_of_type<5 * isq::frequency[Hz] + quantity_point{10 / (2 * isq::period_duration[s])}, quantity_point, int>>); static_assert(is_of_type, int>>); static_assert(is_of_type, int>>); static_assert(is_of_type>); static_assert(is_of_type>); // Different named dimensions template consteval bool invalid_addition(Ts... ts) { return !requires { (... + ts); }; } template consteval bool invalid_subtraction(Ts... ts) { return !requires { (... - ts); }; } inline constexpr struct zero_Bq final : absolute_point_origin> { } zero_Bq; static_assert(invalid_addition(zero_Bq + 5 * isq::activity[Bq], 5 * isq::frequency[Hz])); static_assert(invalid_addition(5 * isq::activity[Bq], zero_Hz + 5 * isq::frequency[Hz])); static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], 5 * isq::frequency[Hz])); static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], zero_Hz + 5 * isq::frequency[Hz])); static_assert(invalid_addition(zero_Bq + 5 * isq::activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); static_assert(invalid_addition(5 * isq::activity[Bq], zero_Hz + 10 / (2 * isq::period_duration[s]), 5 * isq::frequency[Hz])); static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), zero_Hz + 5 * isq::frequency[Hz])); static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); static_assert(invalid_addition(quantity_point{5 * isq::activity[Bq]}, 5 * isq::frequency[Hz])); static_assert(invalid_addition(5 * isq::activity[Bq], quantity_point{5 * isq::frequency[Hz]})); static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, 5 * isq::frequency[Hz])); static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, quantity_point{5 * isq::frequency[Hz]})); static_assert(invalid_addition(quantity_point{5 * isq::activity[Bq]}, 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); static_assert(invalid_addition(5 * isq::activity[Bq], quantity_point{10 / (2 * isq::time[s])}, 5 * isq::frequency[Hz])); static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), quantity_point{5 * isq::frequency[Hz]})); static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); // value_cast static_assert(value_cast(quantity_point{2 * km}).quantity_from_zero().numerical_value_in(m) == 2000); static_assert(value_cast(quantity_point{2000 * m}).quantity_from_zero().numerical_value_in(km) == 2); static_assert(value_cast(quantity_point{1.23 * m}).quantity_from_zero().numerical_value_in(m) == 1); static_assert( value_cast(quantity_point{2000.0 * m / (3600.0 * s)}).quantity_from_zero().numerical_value_in(km / h) == 2); // lvalue references in value_cast namespace lvalue_tests { constexpr quantity_point lvalue_qp{2 * km}; static_assert(value_cast(lvalue_qp).quantity_from_zero().numerical_value_in(m) == 2000); static_assert(value_cast(lvalue_qp).quantity_from_zero().numerical_value_in(km) == 2.f); static_assert(value_cast(lvalue_qp).quantity_from_zero().numerical_value_in(m) == 2000.f); static_assert(value_cast(lvalue_qp).quantity_from_zero().numerical_value_in(m) == 2000.f); } // namespace lvalue_tests static_assert(value_cast>(quantity_point{2000 * m}).quantity_from_zero().numerical_value_in(km) == 2); static_assert(value_cast>(quantity_point{2000 * m}).quantity_from_zero().numerical_value_in(km) == 2); template constexpr bool value_cast_is_forbidden() { // it appears we cannot have the requires clause right inside static_assert return !requires(FromQ q) { value_cast(q); }; } static_assert(value_cast_is_forbidden, quantity_point>(), "value_cast shall not cast between different quantity types"); static_assert(value_cast_is_forbidden, quantity_point>(), "value_cast shall not cast between different quantity types"); // value_cast which does not touch the point_origin static_assert(value_cast>(quantity_point{2 * isq::height[km]}) .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(m) == 2000); static_assert(value_cast>(quantity_point{2000 * isq::height[m]}) .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(km) == 2); // a value_cast which includes a change to the point origin static_assert(value_cast>(quantity_point{2000 * isq::height[m], ground_level}) .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(m) == 2042); // a value_cast which includes a change to the point origin as-well as a change in units static_assert(value_cast>(quantity_point{2 * isq::height[km], ground_level}) .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(m) == 2042); // a value_cast which changes all three of unit, rep, point_origin simultaneously, and the range of either FromQP or // ToQP does not include the other's point_origin static_assert(value_cast>( quantity_point{std::int8_t{100} * isq::height[mm], ground_level}) .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(cm) == 4210); static_assert(value_cast>( quantity_point{4210 * isq::height[cm], mean_sea_level}) .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(mm) == 100); } // namespace