Files
mp-units/test/static/quantity_point_test.cpp

1780 lines
109 KiB
C++

// 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 <mp-units/compat_macros.h>
#include <mp-units/ext/type_traits.h>
#include <mp-units/systems/isq.h>
#include <mp-units/systems/si.h>
#include <mp-units/systems/usc.h>
#ifdef MP_UNITS_IMPORT_STD
import std;
#else
#include <concepts>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
#if MP_UNITS_HOSTED
#include <chrono>
#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<std::chrono::system_clock, std::chrono::seconds>;
#endif
inline constexpr struct zeroth_length final : absolute_point_origin<isq::length> {
} zeroth_length;
inline constexpr struct mean_sea_level final : absolute_point_origin<isq::height> {
} mean_sea_level;
inline constexpr auto my_mean_sea_level = mean_sea_level;
inline constexpr struct same_mean_sea_level final : relative_point_origin<mean_sea_level + 0 * isq::height[m]> {
} same_mean_sea_level;
inline constexpr struct ground_level final : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
} ground_level;
inline constexpr auto my_ground_level = ground_level;
inline constexpr struct same_ground_level1 final : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
} same_ground_level1;
inline constexpr struct same_ground_level2 final : relative_point_origin<my_mean_sea_level + 42 * isq::height[m]> {
} same_ground_level2;
inline constexpr struct tower_peak final : relative_point_origin<ground_level + 42 * isq::height[m]> {
} tower_peak;
inline constexpr struct other_ground_level final : relative_point_origin<mean_sea_level + 123 * isq::height[m]> {
} other_ground_level;
inline constexpr struct other_absolute_level final : absolute_point_origin<isq::height> {
} other_absolute_level;
inline constexpr struct zero final : absolute_point_origin<dimensionless> {
} 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<auto QS>
struct absolute_po_ final : absolute_point_origin<QS> {};
template<auto QS>
constexpr absolute_po_<QS> absolute_po;
template<auto QP>
struct relative_po_ final : relative_point_origin<QP> {};
template<auto QP>
constexpr relative_po_<QP> relative_po;
static_assert(relative_po<absolute_po<isq::length> + isq::height(42 * m)>._quantity_spec_ == isq::height);
static_assert(relative_po<absolute_po<kind_of<isq::length>> + isq::height(42 * m)>._quantity_spec_ == isq::height);
static_assert(relative_po<absolute_po<isq::height> + 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::kelvin>) == 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<kind_of<isq::length>>);
static_assert(default_point_origin(si::kelvin / si::second) ==
zeroth_point_origin<kind_of<isq::thermodynamic_temperature / isq::time>>);
static_assert(default_point_origin(si::degree_Celsius / si::second) ==
zeroth_point_origin<kind_of<isq::thermodynamic_temperature / isq::time>>);
static_assert(zeroth_point_origin<isq::length / isq::time> == zeroth_point_origin<isq::speed>);
static_assert(zeroth_point_origin<inverse(isq::period_duration)> == zeroth_point_origin<isq::frequency>);
static_assert(zeroth_point_origin<kind_of<isq::length>> == zeroth_point_origin<isq::height>);
static_assert(zeroth_point_origin<kind_of<inverse(isq::time)>> == zeroth_point_origin<isq::frequency>);
static_assert(zeroth_point_origin<isq::length> != zeroth_point_origin<isq::height>);
static_assert(zeroth_point_origin<isq::width> != zeroth_point_origin<isq::height>);
static_assert(zeroth_point_origin<inverse(isq::time)> != zeroth_point_origin<isq::frequency>);
/////////////////////
// class invariants
/////////////////////
static_assert(sizeof(quantity_point<si::metre, mean_sea_level>) == sizeof(double));
static_assert(sizeof(quantity_point<isq::height[m], mean_sea_level>) == sizeof(double));
static_assert(sizeof(quantity_point<si::metre, ground_level, short>) == sizeof(short));
static_assert(sizeof(quantity_point<isq::height[m], ground_level, short>) == sizeof(short));
template<template<auto, auto, typename> typename QP>
concept invalid_types = requires {
// unit of a different dimension
requires !requires { typename QP<si::second, mean_sea_level, int>; };
requires !requires { typename QP<si::second, ground_level, int>; };
// incompatible quantity_spec in the origin and quantity_point
requires !requires { typename QP<isq::width[m], mean_sea_level, int>; };
requires !requires { typename QP<isq::width[m], ground_level, int>; };
requires !requires { typename QP<isq::length[m], mean_sea_level, int>; };
requires !requires { typename QP<isq::length[m], ground_level, int>; };
requires !requires { typename QP<isq::length[m], zeroth_point_origin<isq::height>, int>; };
requires !requires { typename QP<isq::width[m], zeroth_point_origin<isq::height>, int>; };
// quantity used as Rep
requires !requires { typename QP<si::metre, mean_sea_level, quantity<si::metre, int>>; };
// quantity point used as Rep
requires !requires { typename QP<si::metre, mean_sea_level, quantity_point<si::metre, mean_sea_level>>; };
// reordered arguments
requires !requires { typename QP<mean_sea_level, si::metre, double>; };
// quantity_spec used as origin
requires !requires { typename QP<si::metre, isq::length, int>; };
// quantity_spec used as a reference
requires !requires { typename QP<isq::length, mean_sea_level, int>; };
// dimension used as a reference
requires !requires { typename QP<isq::dim_length, mean_sea_level, int>; };
// bool used as a representation type
requires !requires { typename QP<si::metre, mean_sea_level, bool>; };
};
static_assert(invalid_types<quantity_point>);
template<template<auto, auto, typename> typename QP>
concept valid_types = requires {
typename QP<si::metre, mean_sea_level, int>;
typename QP<isq::height[m], mean_sea_level, int>;
typename QP<special_height[m], mean_sea_level, int>;
typename QP<si::metre, ground_level, int>;
typename QP<isq::height[m], ground_level, int>;
typename QP<special_height[m], ground_level, int>;
typename QP<isq::height[m], zeroth_point_origin<isq::length>, int>;
typename QP<isq::height[m], zeroth_point_origin<kind_of<isq::length>>, int>;
typename QP<si::metre, zeroth_point_origin<isq::height>, int>;
};
static_assert(valid_types<quantity_point>);
static_assert(std::is_trivially_default_constructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_trivially_copy_constructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_trivially_move_constructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_trivially_copy_assignable_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_trivially_move_assignable_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_trivially_destructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_nothrow_default_constructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_nothrow_copy_constructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_nothrow_move_constructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_nothrow_copy_assignable_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_nothrow_move_assignable_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_nothrow_destructible_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_trivially_copyable_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::is_standard_layout_v<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::default_initializable<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::move_constructible<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::copy_constructible<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::equality_comparable<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::totally_ordered<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::regular<quantity_point<si::metre, mean_sea_level>>);
static_assert(std::three_way_comparable<quantity_point<si::metre, mean_sea_level>>);
//////////////////
// member values
//////////////////
static_assert(quantity_point<si::metre>::reference == si::metre);
static_assert(quantity_point<si::metre>::quantity_spec == kind_of<isq::length>);
static_assert(quantity_point<si::metre>::dimension == isq::dim_length);
static_assert(quantity_point<si::metre>::unit == si::metre);
static_assert(is_of_type<quantity_point<si::metre>::point_origin, zeroth_point_origin_<kind_of<isq::length>>>);
static_assert(is_of_type<quantity_point<si::metre>::absolute_point_origin, zeroth_point_origin_<kind_of<isq::length>>>);
static_assert(quantity_point<isq::height[m]>::reference == isq::height[m]);
static_assert(quantity_point<isq::height[m]>::quantity_spec == isq::height);
static_assert(quantity_point<isq::height[m]>::dimension == isq::dim_length);
static_assert(quantity_point<isq::height[m]>::unit == si::metre);
static_assert(is_of_type<quantity_point<isq::height[m]>::point_origin, zeroth_point_origin_<isq::height>>);
static_assert(is_of_type<quantity_point<isq::height[m]>::absolute_point_origin, zeroth_point_origin_<isq::height>>);
static_assert(quantity_point<si::metre, mean_sea_level>::reference == si::metre);
static_assert(quantity_point<si::metre, mean_sea_level>::quantity_spec == kind_of<isq::length>);
static_assert(quantity_point<si::metre, mean_sea_level>::dimension == isq::dim_length);
static_assert(quantity_point<si::metre, mean_sea_level>::unit == si::metre);
static_assert(is_of_type<quantity_point<si::metre, mean_sea_level>::point_origin, struct mean_sea_level>);
static_assert(is_of_type<quantity_point<si::metre, mean_sea_level>::absolute_point_origin, struct mean_sea_level>);
static_assert(quantity_point<isq::height[m], mean_sea_level>::reference == isq::height[m]);
static_assert(quantity_point<isq::height[m], mean_sea_level>::quantity_spec == isq::height);
static_assert(quantity_point<isq::height[m], mean_sea_level>::dimension == isq::dim_length);
static_assert(quantity_point<isq::height[m], mean_sea_level>::unit == si::metre);
static_assert(is_of_type<quantity_point<isq::height[m], mean_sea_level>::point_origin, struct mean_sea_level>);
static_assert(is_of_type<quantity_point<isq::height[m], mean_sea_level>::absolute_point_origin, struct mean_sea_level>);
static_assert(quantity_point<isq::height[m], ground_level>::reference == isq::height[m]);
static_assert(quantity_point<isq::height[m], ground_level>::quantity_spec == isq::height);
static_assert(quantity_point<isq::height[m], ground_level>::dimension == isq::dim_length);
static_assert(quantity_point<isq::height[m], ground_level>::unit == si::metre);
static_assert(is_of_type<quantity_point<isq::height[m], ground_level>::point_origin, struct ground_level>);
static_assert(is_of_type<quantity_point<isq::height[m], ground_level>::absolute_point_origin, struct mean_sea_level>);
static_assert(quantity_point<isq::height[m], tower_peak>::reference == isq::height[m]);
static_assert(quantity_point<isq::height[m], tower_peak>::quantity_spec == isq::height);
static_assert(quantity_point<isq::height[m], tower_peak>::dimension == isq::dim_length);
static_assert(quantity_point<isq::height[m], tower_peak>::unit == si::metre);
static_assert(is_of_type<quantity_point<isq::height[m], tower_peak>::point_origin, struct tower_peak>);
static_assert(is_of_type<quantity_point<isq::height[m], tower_peak>::absolute_point_origin, struct mean_sea_level>);
static_assert(quantity_point<si::kelvin, si::absolute_zero>::reference == si::kelvin);
static_assert(quantity_point<si::kelvin, si::absolute_zero>::quantity_spec == kind_of<isq::thermodynamic_temperature>);
static_assert(quantity_point<si::kelvin, si::absolute_zero>::dimension == isq::dim_thermodynamic_temperature);
static_assert(quantity_point<si::kelvin, si::absolute_zero>::unit == si::kelvin);
static_assert(is_of_type<quantity_point<si::kelvin, si::absolute_zero>::point_origin, struct si::absolute_zero>);
static_assert(
is_of_type<quantity_point<si::kelvin, si::absolute_zero>::absolute_point_origin, struct si::absolute_zero>);
static_assert(quantity_point<isq::thermodynamic_temperature[si::kelvin], si::absolute_zero>::reference ==
isq::thermodynamic_temperature[si::kelvin]);
static_assert(quantity_point<isq::thermodynamic_temperature[si::kelvin], si::absolute_zero>::quantity_spec ==
isq::thermodynamic_temperature);
static_assert(quantity_point<isq::thermodynamic_temperature[si::kelvin], si::absolute_zero>::dimension ==
isq::dim_thermodynamic_temperature);
static_assert(quantity_point<isq::thermodynamic_temperature[si::kelvin], si::absolute_zero>::unit == si::kelvin);
static_assert(is_of_type<quantity_point<isq::thermodynamic_temperature[si::kelvin], si::absolute_zero>::point_origin,
struct si::absolute_zero>);
static_assert(
is_of_type<quantity_point<isq::thermodynamic_temperature[si::kelvin], si::absolute_zero>::absolute_point_origin,
struct si::absolute_zero>);
static_assert(quantity_point<isq::Celsius_temperature[si::kelvin], si::absolute_zero>::reference ==
isq::Celsius_temperature[si::kelvin]);
static_assert(quantity_point<isq::Celsius_temperature[si::kelvin], si::absolute_zero>::quantity_spec ==
isq::Celsius_temperature);
static_assert(quantity_point<isq::Celsius_temperature[si::kelvin], si::absolute_zero>::dimension ==
isq::dim_thermodynamic_temperature);
static_assert(quantity_point<isq::Celsius_temperature[si::kelvin], si::absolute_zero>::unit == si::kelvin);
static_assert(is_of_type<quantity_point<isq::Celsius_temperature[si::kelvin], si::absolute_zero>::point_origin,
struct si::absolute_zero>);
static_assert(is_of_type<quantity_point<isq::Celsius_temperature[si::kelvin], si::absolute_zero>::absolute_point_origin,
struct si::absolute_zero>);
static_assert(quantity_point<si::degree_Celsius, si::ice_point>::reference == si::degree_Celsius);
static_assert(quantity_point<si::degree_Celsius, si::ice_point>::quantity_spec ==
kind_of<isq::thermodynamic_temperature>);
static_assert(quantity_point<si::degree_Celsius, si::ice_point>::dimension == isq::dim_thermodynamic_temperature);
static_assert(quantity_point<si::degree_Celsius, si::ice_point>::unit == si::degree_Celsius);
static_assert(is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::point_origin, struct si::ice_point>);
static_assert(
is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::absolute_point_origin, struct si::absolute_zero>);
static_assert(quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::reference ==
isq::Celsius_temperature[si::degree_Celsius]);
static_assert(quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::quantity_spec ==
isq::Celsius_temperature);
static_assert(quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::dimension ==
isq::dim_thermodynamic_temperature);
static_assert(quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::unit == si::degree_Celsius);
static_assert(is_of_type<quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::point_origin,
struct si::ice_point>);
static_assert(
is_of_type<quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::absolute_point_origin,
struct si::absolute_zero>);
//////////////////
// member types
//////////////////
static_assert(is_same_v<quantity_point<si::metre, mean_sea_level>::rep, double>);
static_assert(is_same_v<quantity_point<si::metre, mean_sea_level>::quantity_type, quantity<si::metre>>);
static_assert(is_same_v<quantity_point<si::metre, mean_sea_level, int>::rep, int>);
static_assert(is_same_v<quantity_point<si::metre, mean_sea_level, int>::quantity_type, quantity<si::metre, int>>);
static_assert(is_same_v<quantity_point<isq::height[m], mean_sea_level>::rep, double>);
static_assert(is_same_v<quantity_point<isq::height[m], mean_sea_level>::quantity_type, quantity<isq::height[m]>>);
static_assert(is_same_v<quantity_point<isq::height[m], mean_sea_level, int>::rep, int>);
static_assert(
is_same_v<quantity_point<isq::height[m], mean_sea_level, int>::quantity_type, quantity<isq::height[m], int>>);
////////////////////////////
// static member functions
////////////////////////////
static_assert(
quantity_point<isq::height[m], mean_sea_level>::min().quantity_from(mean_sea_level).numerical_value_in(m) ==
std::numeric_limits<double>::lowest());
static_assert(
quantity_point<isq::height[m], mean_sea_level>::max().quantity_from(mean_sea_level).numerical_value_in(m) ==
std::numeric_limits<double>::max());
static_assert(
quantity_point<isq::height[m], ground_level, int>::min().quantity_from(ground_level).numerical_value_in(m) ==
std::numeric_limits<int>::lowest());
static_assert(
quantity_point<isq::height[m], ground_level, int>::max().quantity_from(ground_level).numerical_value_in(m) ==
std::numeric_limits<int>::max());
//////////////////////////////
// construction from a value
//////////////////////////////
// there is no construction from a value
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, double>);
static_assert(!std::convertible_to<double, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], ground_level, int>, int>);
static_assert(!std::convertible_to<int, quantity_point<isq::height[m], ground_level, int>>);
static_assert(!std::constructible_from<quantity_point<dimensionless[percent], zero>, double>);
static_assert(!std::convertible_to<double, quantity_point<dimensionless[percent], zero>>);
static_assert(!std::constructible_from<quantity_point<dimensionless[percent], zero, int>, int>);
static_assert(!std::convertible_to<int, quantity_point<dimensionless[percent], zero, int>>);
static_assert(!std::constructible_from<quantity_point<dimensionless[one], zero>, double>);
static_assert(!std::convertible_to<double, quantity_point<dimensionless[one], zero>>);
static_assert(!std::constructible_from<quantity_point<dimensionless[one], zero, int>, int>);
static_assert(!std::convertible_to<int, quantity_point<dimensionless[one], zero, int>>);
/////////////////////////////////
// construction from a quantity
/////////////////////////////////
// -----------------------------
// implicit zeroth point origins
// -----------------------------
static_assert(std::constructible_from<quantity_point<si::metre>, quantity<si::metre>>);
static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<si::metre>>);
static_assert(std::constructible_from<quantity_point<isq::height[m]>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::height[m]>>);
static_assert(std::constructible_from<quantity_point<isq::height[m]>, quantity<si::metre>>);
static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<isq::height[m]>>);
static_assert(std::constructible_from<quantity_point<si::metre>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<si::metre>>);
static_assert(std::constructible_from<quantity_point<m / s>, quantity<isq::speed[m / s]>>);
static_assert(!std::convertible_to<quantity<isq::speed[m / s]>, quantity_point<m / s>>);
static_assert(std::constructible_from<quantity_point<isq::speed[m / s]>, quantity<m / s>>);
static_assert(!std::convertible_to<quantity<m / s>, quantity_point<isq::speed[m / s]>>);
static_assert(std::constructible_from<quantity_point<isq::length[m] / isq::time[s]>, quantity<isq::speed[m / s]>>);
static_assert(!std::convertible_to<quantity<isq::speed[m / s]>, quantity_point<isq::length[m] / isq::time[s]>>);
static_assert(std::constructible_from<quantity_point<isq::speed[m / s]>, quantity<isq::length[m] / isq::time[s]>>);
static_assert(!std::convertible_to<quantity<isq::length[m] / isq::time[s]>, quantity_point<isq::speed[m / s]>>);
static_assert(std::constructible_from<quantity_point<isq::speed[m / s]>, quantity<m / s>>);
static_assert(!std::convertible_to<quantity<m / s>, quantity_point<isq::speed[m / s]>>);
static_assert(std::constructible_from<quantity_point<dimensionless[one]>, quantity<dimensionless[one]>>);
static_assert(!std::convertible_to<quantity<dimensionless[one]>, quantity_point<dimensionless[one]>>);
// different dimensions
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity<si::second>>);
static_assert(!std::convertible_to<quantity<si::second>, quantity_point<isq::height[m]>>);
// convertible but different quantity_specs
static_assert(std::constructible_from<quantity_point<isq::length[m]>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::length[m]>>);
static_assert(std::constructible_from<quantity_point<isq::height[m]>, quantity<special_height[m]>>);
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m]>>);
// quantity_specs with get_common_quantity_spec
static_assert(!std::constructible_from<quantity_point<isq::width[m]>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::width[m]>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity<isq::width[m]>>);
static_assert(!std::convertible_to<quantity<isq::width[m]>, quantity_point<isq::height[m]>>);
// non-convertible quantity_specs
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity<isq::length[m]>>);
static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<isq::height[m]>>);
static_assert(!std::constructible_from<quantity_point<special_height[m]>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m]>>);
#if MP_UNITS_HOSTED
// quantity-like
static_assert(!std::constructible_from<quantity_point<si::second>, std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<si::second>>);
static_assert(!std::constructible_from<quantity_point<isq::time[s]>, std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<isq::time[s]>>);
static_assert(!std::constructible_from<quantity_point<isq::period_duration[s]>, std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<isq::period_duration[s]>>);
#endif
// ----------------------
// explicit point origins
// ----------------------
static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<si::metre>>);
static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<si::metre, mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<si::metre>>);
static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<si::metre, mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<special_height[m]>>);
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<dimensionless[one], zero>, quantity<dimensionless[one]>>);
static_assert(!std::convertible_to<quantity<dimensionless[one]>, quantity_point<dimensionless[one], zero>>);
// quantity_specs with get_common_quantity_spec
static_assert(!std::constructible_from<quantity_point<isq::width[m], zeroth_length>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::width[m], zeroth_length>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], zeroth_length>, quantity<isq::width[m]>>);
static_assert(!std::convertible_to<quantity<isq::width[m]>, quantity_point<isq::height[m], zeroth_length>>);
// different dimensions
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<si::second>>);
static_assert(!std::convertible_to<quantity<si::second>, quantity_point<isq::height[m], mean_sea_level>>);
// non-convertible quantity_specs
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<isq::length[m]>>);
static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<special_height[m], mean_sea_level>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
// not-compatible origin
static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<isq::length[m]>>);
static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<si::metre, mean_sea_level>>);
#if MP_UNITS_HOSTED
// quantity-like
static_assert(!std::constructible_from<quantity_point<si::second, chrono_point_origin<std::chrono::system_clock>>,
std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds,
quantity_point<si::second, chrono_point_origin<std::chrono::system_clock>>>);
static_assert(!std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>,
std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds,
quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>>);
static_assert(
!std::constructible_from<quantity_point<isq::period_duration[s], chrono_point_origin<std::chrono::system_clock>>,
std::chrono::seconds>);
static_assert(
!std::convertible_to<std::chrono::seconds,
quantity_point<isq::period_duration[s], chrono_point_origin<std::chrono::system_clock>>>);
#endif
///////////////////////////////////////
// construction from a quantity point
///////////////////////////////////////
// implicit origin
static_assert(std::constructible_from<quantity_point<si::metre>, quantity_point<si::metre>>);
static_assert(std::convertible_to<quantity_point<si::metre>, quantity_point<si::metre>>);
static_assert(std::constructible_from<quantity_point<isq::height[m]>, quantity_point<isq::height[m]>>);
static_assert(std::convertible_to<quantity_point<isq::height[m]>, quantity_point<isq::height[m]>>);
static_assert(std::constructible_from<quantity_point<si::metre>, quantity_point<isq::height[m]>>);
static_assert(std::convertible_to<quantity_point<isq::height[m]>, quantity_point<si::metre>>);
static_assert(std::constructible_from<quantity_point<isq::height[m]>, quantity_point<si::metre>>);
static_assert(std::convertible_to<quantity_point<si::metre>, quantity_point<isq::height[m]>>);
static_assert(
std::constructible_from<quantity_point<isq::length[m] / isq::time[s]>, quantity_point<isq::speed[m / s]>>);
static_assert(std::convertible_to<quantity_point<isq::speed[m / s]>, quantity_point<isq::length[m] / isq::time[s]>>);
static_assert(std::constructible_from<quantity_point<m / s>, quantity_point<isq::speed[m / s]>>);
static_assert(std::convertible_to<quantity_point<isq::speed[m / s]>, quantity_point<m / s>>);
static_assert(std::constructible_from<quantity_point<m / s>, quantity_point<isq::length[m] / isq::time[s]>>);
static_assert(std::convertible_to<quantity_point<isq::length[m] / isq::time[s]>, quantity_point<m / s>>);
// convertible but different quantity_specs
static_assert(!std::constructible_from<quantity_point<isq::length[m]>, quantity_point<isq::height[m]>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m]>, quantity_point<isq::length[m]>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity_point<special_height[m]>>);
static_assert(!std::convertible_to<quantity_point<special_height[m]>, quantity_point<isq::height[m]>>);
// quantity_specs with get_common_quantity_spec
static_assert(!std::constructible_from<quantity_point<isq::width[m]>, quantity_point<isq::height[m]>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m]>, quantity_point<isq::width[m]>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity_point<isq::width[m]>>);
static_assert(!std::convertible_to<quantity_point<isq::width[m]>, quantity_point<isq::height[m]>>);
// non-convertible quantity_specs
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity_point<isq::length[m]>>);
static_assert(!std::convertible_to<quantity_point<isq::length[m]>, quantity_point<isq::height[m]>>);
static_assert(!std::constructible_from<quantity_point<special_height[m]>, quantity_point<isq::height[m]>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m]>, quantity_point<special_height[m]>>);
// mixed origins
static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity_point<si::metre>>);
static_assert(!std::convertible_to<quantity_point<si::metre>, quantity_point<si::metre, mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity_point<isq::height[m]>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<si::metre>, quantity_point<si::metre, mean_sea_level>>);
static_assert(!std::convertible_to<quantity_point<si::metre, mean_sea_level>, quantity_point<si::metre>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], mean_sea_level>, quantity_point<isq::height[m]>>);
// same explicit origins
static_assert(
std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<si::metre, mean_sea_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[km], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], mean_sea_level>, quantity_point<isq::height[km], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[km], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[km], mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], mean_sea_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<si::metre, mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<special_height[m], mean_sea_level>>);
static_assert(std::convertible_to<quantity_point<special_height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, ground_level>, quantity_point<si::metre, ground_level>>);
static_assert(std::convertible_to<quantity_point<si::metre, ground_level>, quantity_point<si::metre, ground_level>>);
static_assert(
std::constructible_from<quantity_point<isq::height[m], ground_level>, quantity_point<isq::height[m], ground_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], ground_level>, quantity_point<isq::height[m], ground_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[km], ground_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], ground_level>, quantity_point<isq::height[km], mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<isq::height[m], ground_level>, quantity_point<isq::height[km], ground_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[km], ground_level>, quantity_point<isq::height[m], ground_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, ground_level>, quantity_point<isq::height[m], ground_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], ground_level>, quantity_point<si::metre, ground_level>>);
static_assert(
std::constructible_from<quantity_point<isq::height[m], ground_level>, quantity_point<si::metre, ground_level>>);
static_assert(
std::convertible_to<quantity_point<si::metre, ground_level>, quantity_point<isq::height[m], ground_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], ground_level>,
quantity_point<special_height[m], ground_level>>);
static_assert(
std::convertible_to<quantity_point<special_height[m], ground_level>, quantity_point<isq::height[m], ground_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity_point<si::metre, ground_level>>);
static_assert(std::convertible_to<quantity_point<si::metre, ground_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, ground_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(std::convertible_to<quantity_point<si::metre, mean_sea_level>, quantity_point<si::metre, ground_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, ground_level>, quantity_point<si::metre, other_ground_level>>);
static_assert(
std::convertible_to<quantity_point<si::metre, other_ground_level>, quantity_point<si::metre, ground_level>>);
static_assert(
std::constructible_from<quantity_point<dimensionless[one], zero>, quantity_point<dimensionless[one], zero>>);
static_assert(std::convertible_to<quantity_point<dimensionless[one], zero>, quantity_point<dimensionless[one], zero>>);
static_assert(
std::constructible_from<quantity_point<dimensionless[one], zero>, quantity_point<dimensionless[percent], zero>>);
static_assert(
std::convertible_to<quantity_point<dimensionless[percent], zero>, quantity_point<dimensionless[one], zero>>);
static_assert(
std::constructible_from<quantity_point<dimensionless[percent], zero>, quantity_point<dimensionless[one], zero>>);
static_assert(
std::convertible_to<quantity_point<dimensionless[one], zero>, quantity_point<dimensionless[percent], zero>>);
static_assert(std::constructible_from<quantity_point<isq::length[m], zeroth_length>,
quantity_point<isq::height[m], zeroth_length>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], zeroth_length>, quantity_point<isq::length[m], zeroth_length>>);
// quantity_specs with get_common_quantity_spec
static_assert(!std::constructible_from<quantity_point<isq::width[m], zeroth_length>,
quantity_point<isq::height[m], zeroth_length>>);
static_assert(
!std::convertible_to<quantity_point<isq::height[m], zeroth_length>, quantity_point<isq::width[m], zeroth_length>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], zeroth_length>,
quantity_point<isq::width[m], zeroth_length>>);
static_assert(
!std::convertible_to<quantity_point<isq::width[m], zeroth_length>, quantity_point<isq::height[m], zeroth_length>>);
// different dimensions
static_assert(
!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity_point<si::kelvin, si::ice_point>>);
static_assert(
!std::convertible_to<quantity_point<si::kelvin, si::ice_point>, quantity_point<isq::height[m], mean_sea_level>>);
// non-convertible quantity_specs
static_assert(std::constructible_from<quantity_point<special_height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<special_height[m], mean_sea_level>>);
// implicit conversion from another quantity point only if non-truncating
// int -> double OK
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(std::convertible_to<quantity_point<isq::height[m], mean_sea_level, int>,
quantity_point<isq::height[m], mean_sea_level>>);
// truncating double -> int not allowed
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level, int>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level, int>>);
// kilometre<int> -> metre<int> OK
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level, int>,
quantity_point<isq::height[km], mean_sea_level, int>>);
static_assert(std::convertible_to<quantity_point<isq::height[km], mean_sea_level, int>,
quantity_point<isq::height[m], mean_sea_level, int>>);
// truncating metre<int> -> kilometre<int> not allowed
static_assert(!std::constructible_from<quantity_point<isq::height[km], mean_sea_level, int>,
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], mean_sea_level, int>,
quantity_point<isq::height[km], mean_sea_level, int>>);
// converting to double always OK
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[km], mean_sea_level, int>>);
static_assert(std::convertible_to<quantity_point<isq::height[km], mean_sea_level, int>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[km], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(std::convertible_to<quantity_point<isq::height[m], mean_sea_level, int>,
quantity_point<isq::height[km], mean_sea_level>>);
// same but not a default origin
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<isq::height[m], mean_sea_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(
std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity_point<si::metre, mean_sea_level>>);
static_assert(
std::convertible_to<quantity_point<si::metre, mean_sea_level>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<special_height[m], mean_sea_level>>);
static_assert(std::convertible_to<quantity_point<special_height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<special_height[m], mean_sea_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<special_height[m], mean_sea_level>>);
// different origins
static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>,
quantity_point<isq::height[m], other_absolute_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], other_absolute_level>,
quantity_point<isq::height[m], mean_sea_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], ground_level>,
quantity_point<isq::height[m], other_absolute_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], other_absolute_level>,
quantity_point<isq::height[m], ground_level>>);
static_assert(!std::constructible_from<quantity_point<isq::height[m], other_absolute_level>,
quantity_point<isq::height[m], ground_level>>);
static_assert(!std::convertible_to<quantity_point<isq::height[m], ground_level>,
quantity_point<isq::height[m], other_absolute_level>>);
#if MP_UNITS_HOSTED
// quantity-point-like
static_assert(
std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>, sys_seconds>);
static_assert(
std::convertible_to<sys_seconds, quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>>);
// incompatible origin
static_assert(
!std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::steady_clock>>, sys_seconds>);
static_assert(
!std::convertible_to<sys_seconds, quantity_point<isq::time[s], chrono_point_origin<std::chrono::steady_clock>>>);
#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<deg_C>(20)}.quantity_from_zero() == delta<deg_C>(20));
static_assert(quantity_point{delta<deg_C>(20.)}.in(deg_F).quantity_from_zero() == delta<deg_F>(68));
static_assert(point<deg_C>(20).quantity_from_zero() == delta<deg_C>(20));
static_assert(point<deg_C>(20.).in(deg_F).quantity_from_zero() == delta<deg_F>(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<isq::height[m], mean_sea_level>(ground_level + 42 * m).quantity_from(mean_sea_level) ==
84 * m);
static_assert(quantity_point<isq::height[m], mean_sea_level>(tower_peak + 42 * m).quantity_from(mean_sea_level) ==
126 * m);
static_assert(quantity_point<isq::height[m], ground_level>(mean_sea_level + 84 * m).quantity_from(ground_level) ==
42 * m);
static_assert(quantity_point<isq::height[m], ground_level>(tower_peak + 42 * m).quantity_from(ground_level) == 84 * m);
static_assert(quantity_point<isq::height[m], tower_peak>(mean_sea_level + 42 * m).quantity_from(tower_peak) == -42 * m);
static_assert(quantity_point<isq::height[m], tower_peak>(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<isq::height[m], mean_sea_level, int>>);
///////////////////////////////////
// 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<m, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 2 * km).in<double>(), quantity_point<km, mean_sea_level>>);
static_assert(is_of_type<(mean_sea_level + 2 * km).in<double>(m), quantity_point<m, mean_sea_level>>);
static_assert(is_of_type<(mean_sea_level + 2500. * m).force_in(km), quantity_point<km, mean_sea_level>>);
static_assert(is_of_type<(mean_sea_level + 2500. * m).force_in<int>(), quantity_point<m, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 2500. * m).force_in<int>(km), quantity_point<km, mean_sea_level, int>>);
template<template<auto, auto, typename> typename QP>
concept invalid_unit_conversion = requires {
requires !requires { QP<isq::height[m], mean_sea_level, int>(2000 * m).in(km); }; // truncating conversion
requires !requires { QP<isq::height[m], mean_sea_level, int>(2 * m).in(s); }; // invalid unit
};
static_assert(invalid_unit_conversion<quantity_point>);
/////////
// CTAD
/////////
static_assert(std::is_same_v<decltype(quantity_point{123 * m})::rep, int>);
static_assert(std::is_same_v<MP_UNITS_NONCONST_TYPE(quantity_point{123 * m}.point_origin),
zeroth_point_origin_<kind_of<isq::length>>>);
static_assert(std::is_same_v<MP_UNITS_NONCONST_TYPE(quantity_point{123 * m}.absolute_point_origin),
zeroth_point_origin_<kind_of<isq::length>>>);
static_assert(quantity_point{123 * m}.unit == si::metre);
static_assert(quantity_point{123 * m}.quantity_spec == kind_of<isq::length>);
static_assert(std::is_same_v<decltype(quantity_point{isq::height(123 * m)})::rep, int>);
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{isq::height(123 * m)}.point_origin)>,
zeroth_point_origin_<isq::height>>);
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{isq::height(123 * m)}.absolute_point_origin)>,
zeroth_point_origin_<isq::height>>);
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<decltype(quantity_point{delta<deg_C>(20)})::rep, int>);
static_assert(
std::is_same_v<std::remove_const_t<decltype(quantity_point{delta<deg_C>(20)}.point_origin)>, struct si::ice_point>);
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{delta<deg_C>(20)}.absolute_point_origin)>,
struct si::absolute_zero>);
static_assert(quantity_point{delta<deg_C>(20)}.unit == si::degree_Celsius);
static_assert(quantity_point{delta<deg_C>(20)}.quantity_spec == kind_of<isq::thermodynamic_temperature>);
#if MP_UNITS_HOSTED
using namespace std::chrono_literals;
static_assert(std::is_same_v<decltype(quantity_point{sys_seconds{123s}})::rep, std::chrono::seconds::rep>);
static_assert(std::is_same_v<MP_UNITS_NONCONST_TYPE(quantity_point{sys_seconds{123s}}.point_origin),
chrono_point_origin_<std::chrono::system_clock>>);
static_assert(std::is_same_v<MP_UNITS_NONCONST_TYPE(quantity_point{sys_seconds{123s}}.absolute_point_origin),
chrono_point_origin_<std::chrono::system_clock>>);
static_assert(quantity_point{sys_seconds{24h}}.unit == si::second);
static_assert(quantity_point{sys_seconds{24h}}.quantity_spec == kind_of<isq::time>);
#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<template<auto, auto, typename> typename QP>
concept invalid_compound_assignments = requires() {
// truncating not allowed
requires !requires(QP<isq::height[m], mean_sea_level, int> l) { l += 2.5 * m; };
requires !requires(QP<isq::height[m], mean_sea_level, int> l) { l -= 2.5 * m; };
requires !requires(QP<isq::height[km], mean_sea_level, int> l) { l += 2 * isq::height[m]; };
requires !requires(QP<isq::height[km], mean_sea_level, int> l) { l -= 2 * isq::height[m]; };
// only quantities can be added or subtracted
requires !requires(QP<isq::height[m], mean_sea_level, int> l) { l += 2; };
requires !requires(QP<isq::height[m], mean_sea_level, int> l) { l -= 2; };
// no unit constants
requires !requires(QP<isq::height[m], mean_sea_level, int> l) { l += m; };
requires !requires(QP<isq::height[m], mean_sea_level, int> l) { l -= m; };
};
static_assert(invalid_compound_assignments<quantity_point>);
////////////////////
// binary operators
////////////////////
template<template<auto, auto, typename> typename QP, auto Origin, auto OtherOrigin>
concept invalid_binary_operations = requires {
// can't add two quantity points
requires !requires {
QP<isq::height[m], mean_sea_level, int>(1 * m) + QP<isq::height[m], mean_sea_level, int>(1 * m);
};
requires !requires { mean_sea_level + QP<isq::height[m], mean_sea_level, int>(1 * m); };
requires !requires { QP<isq::height[m], mean_sea_level, int>(1 * m) + mean_sea_level; };
requires !requires { Origin + Origin; };
// can't add more generic quantity (violates point_origin quantity_spec)
requires !requires { QP<si::metre, mean_sea_level, int>(1 * m) + isq::length(1 * m); };
requires !requires { isq::length(1 * m) + QP<si::metre, mean_sea_level, int>(1 * m); };
requires !requires { QP<isq::height[m], mean_sea_level, int>(1 * m) + isq::length(1 * m); };
requires !requires { isq::length(1 * m) + QP<isq::height[m], mean_sea_level, int>(1 * m); };
requires !requires { QP<si::metre, zeroth_point_origin<isq::height>, int>(1 * m) + isq::length(1 * m); };
requires !requires { isq::length(1 * m) + QP<si::metre, zeroth_point_origin<isq::height>, int>(1 * m); };
requires !requires { QP<isq::height[m], zeroth_point_origin<isq::height>, int>(1 * m) + isq::length(1 * m); };
requires !requires { isq::length(1 * m) + QP<isq::height[m], zeroth_point_origin<isq::height>, 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<si::metre, mean_sea_level, int>(1 * m) - isq::length(1 * m); };
requires !requires { QP<isq::height[m], mean_sea_level, int>(1 * m) - isq::length(1 * m); };
requires !requires { QP<si::metre, zeroth_point_origin<isq::height>, int>(1 * m) - isq::length(1 * m); };
requires !requires { QP<isq::height[m], zeroth_point_origin<isq::height>, int>(1 * m) - isq::length(1 * m); };
requires !requires {
QP<isq::height[m] / isq::time[s], zeroth_point_origin<isq::height / isq::time>, int>(10 * isq::height[m] /
(2 * isq::time[s])) +
5 * isq::speed[m / s];
};
requires !requires {
5 * isq::speed[m / s] + QP<isq::height[m] / isq::time[s], zeroth_point_origin<isq::height / isq::time>, int>(
10 * isq::height[m] / (2 * isq::time[s]));
};
requires !requires {
QP<isq::height[m] / isq::time[s], zeroth_point_origin<isq::height / isq::time>, 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<si::metre, mean_sea_level, int>(1 * m); };
requires !requires { 1 * m - Origin; };
// no crossdimensional addition and subtraction
requires !requires { QP<si::metre, mean_sea_level, int>(1 * m) + 1 * s; };
requires !requires { QP<si::metre, mean_sea_level, int>(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<isq::height[m], mean_sea_level, int>(1 * m) - QP<isq::height[m], other_absolute_level, int>(1 * m);
};
requires !requires {
QP<isq::height[m], other_absolute_level, int>(1 * m) - QP<isq::height[m], mean_sea_level, int>(1 * m);
};
requires !requires { mean_sea_level - QP<isq::height[m], other_absolute_level, int>(1 * m); };
requires !requires { QP<isq::height[m], mean_sea_level, int>(1 * m) - other_absolute_level; };
requires !requires { QP<isq::height[m], mean_sea_level, int>(1 * m) - quantity_point{1 * m}; };
requires !requires { quantity_point{1 * m} - QP<isq::height[m], mean_sea_level, int>(1 * m); };
requires !requires {
QP<isq::width[m], zeroth_point_origin<isq::width>, int>(1 * m) - quantity_point{isq::height(1 * m)};
};
requires !requires {
quantity_point{isq::height(1 * m)} - QP<isq::width[m], zeroth_point_origin<isq::width>, int>(1 * m);
};
requires !requires {
QP<isq::width[m], zeroth_point_origin<isq::width>, int>(1 * m) - quantity_point{isq::length(1 * m)};
};
requires !requires {
quantity_point{isq::length(1 * m)} - QP<isq::width[m], zeroth_point_origin<isq::width>, int>(1 * m);
};
requires !requires {
quantity_point{10 * isq::height[m] / (2 * isq::time[s])} -
QP<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>(5 * isq::speed[m / s]);
};
requires !requires {
QP<isq::speed[m / s], zeroth_point_origin<isq::speed>, 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<si::metre, mean_sea_level, int>(1) + m; };
requires !requires { QP<si::metre, mean_sea_level, int>(1) - m; };
requires !requires { Origin + m; };
requires !requires { Origin - m; };
requires !requires { m + QP<si::metre, mean_sea_level, int>(1); };
requires !requires { m - QP<si::metre, mean_sea_level, int>(1); };
requires !requires { m + Origin; };
requires !requires { m - Origin; };
};
static_assert(invalid_binary_operations<quantity_point, mean_sea_level, other_absolute_level>);
// same representation type
static_assert(is_of_type<(mean_sea_level + 1 * m) + 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) + 1 * km, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) + 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * m) + isq::height(1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * m) + isq::height(1 * km), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * km) + isq::height(1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * m)) + 1 * m, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * m)) + 1 * km, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * km)) + 1 * m, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) + isq::height(1 * m),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) + isq::height(1 * km),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * km)) + isq::height(1 * m),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<1 * m + (mean_sea_level + 1 * m), quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<1 * m + (mean_sea_level + 1 * km), quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<1 * km + (mean_sea_level + 1 * m), quantity_point<si::metre, mean_sea_level, int>>);
static_assert(
is_of_type<1 * m + (mean_sea_level + isq::height(1 * m)), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<1 * m + (mean_sea_level + isq::height(1 * km)), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<1 * km + (mean_sea_level + isq::height(1 * m)), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<isq::height(1 * m) + (mean_sea_level + 1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<isq::height(1 * m) + (mean_sea_level + 1 * km), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<isq::height(1 * km) + (mean_sea_level + 1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<isq::height(1 * m) + (mean_sea_level + isq::height(1 * m)),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<isq::height(1 * m) + (mean_sea_level + isq::height(1 * km)),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<isq::height(1 * km) + (mean_sea_level + isq::height(1 * m)),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level + 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level + 1 * km, quantity_point<si::kilo<si::metre>, mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level + isq::height(1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<mean_sea_level + special_height(1 * m), quantity_point<special_height[si::metre], mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level + special_height(1 * km),
quantity_point<special_height[si::kilo<si::metre>], mean_sea_level, int>>);
static_assert(is_of_type<1 * m + mean_sea_level, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<1 * km + mean_sea_level, quantity_point<si::kilo<si::metre>, mean_sea_level, int>>);
static_assert(is_of_type<isq::height(1 * m) + mean_sea_level, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<special_height(1 * m) + mean_sea_level, quantity_point<special_height[si::metre], mean_sea_level, int>>);
static_assert(is_of_type<special_height(1 * km) + mean_sea_level,
quantity_point<special_height[si::kilo<si::metre>], mean_sea_level, int>>);
static_assert(is_of_type<ground_level + 1 * m, quantity_point<si::metre, ground_level, int>>);
static_assert(is_of_type<ground_level + 1 * km, quantity_point<si::kilo<si::metre>, ground_level, int>>);
static_assert(is_of_type<1 * m + ground_level, quantity_point<si::metre, ground_level, int>>);
static_assert(is_of_type<1 * km + ground_level, quantity_point<si::kilo<si::metre>, ground_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - 1 * km, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * m) - isq::height(1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * m) - isq::height(1 * km), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * km) - isq::height(1 * m), quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * m)) - 1 * m, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * m)) - 1 * km, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * km)) - 1 * m, quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - isq::height(1 * m),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - isq::height(1 * km),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * km)) - isq::height(1 * m),
quantity_point<isq::height[m], mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level - 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level - 1 * km, quantity_point<si::kilo<si::metre>, mean_sea_level, int>>);
static_assert(
is_of_type<mean_sea_level - special_height(1 * m), quantity_point<special_height[si::metre], mean_sea_level, int>>);
static_assert(is_of_type<mean_sea_level - special_height(1 * km),
quantity_point<special_height[si::kilo<si::metre>], mean_sea_level, int>>);
static_assert(is_of_type<ground_level - 1 * m, quantity_point<si::metre, ground_level, int>>);
static_assert(is_of_type<ground_level - 1 * km, quantity_point<si::kilo<si::metre>, ground_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * km), quantity<si::metre, int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + isq::height(1 * m)), quantity<isq::height[m], int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + isq::height(1 * km)), quantity<isq::height[m], int>>);
static_assert(
is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + isq::height(1 * m)), quantity<isq::height[m], int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + 1 * km), quantity<isq::height[m], int>>);
static_assert(
is_of_type<(mean_sea_level + isq::height(1 * km)) - (mean_sea_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + isq::height(1 * m)),
quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * m)) - (mean_sea_level + isq::height(1 * km)),
quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + isq::height(1 * km)) - (mean_sea_level + isq::height(1 * m)),
quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<(ground_level + 1 * m) - (ground_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<(tower_peak + 1 * m) - (tower_peak + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (ground_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(ground_level + 1 * m) - (mean_sea_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(tower_peak + 1 * m) - (ground_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(ground_level + 1 * m) - (tower_peak + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(tower_peak + 1 * m) - (mean_sea_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (tower_peak + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(other_ground_level + 1 * m) - (ground_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(ground_level + 1 * m) - (other_ground_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(other_ground_level + 1 * m) - (tower_peak + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<(tower_peak + 1 * m) - (other_ground_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<mean_sea_level - (mean_sea_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<mean_sea_level - (mean_sea_level + 1 * km), quantity<si::kilo<si::metre>, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - mean_sea_level, quantity<si::metre, int>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - mean_sea_level, quantity<si::kilo<si::metre>, int>>);
static_assert(is_of_type<ground_level - (ground_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<ground_level - (ground_level + 1 * km), quantity<si::kilo<si::metre>, int>>);
static_assert(is_of_type<(ground_level + 1 * m) - ground_level, quantity<si::metre, int>>);
static_assert(is_of_type<(ground_level + 1 * km) - ground_level, quantity<si::kilo<si::metre>, int>>);
static_assert(is_of_type<mean_sea_level - (ground_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<mean_sea_level - (ground_level + 1 * km), quantity<isq::height[m], int>>);
static_assert(is_of_type<(ground_level + 1 * m) - mean_sea_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<(ground_level + 1 * km) - mean_sea_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<ground_level - (mean_sea_level + 1 * m), quantity<isq::height[m], int>>);
static_assert(is_of_type<ground_level - (mean_sea_level + 1 * km), quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - ground_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - ground_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<ground_level - ground_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<mean_sea_level - ground_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<ground_level - mean_sea_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<ground_level - tower_peak, quantity<isq::height[m], int>>);
static_assert(is_of_type<tower_peak - ground_level, quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + mean_sea_level) - (1 * m + ground_level), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + ground_level) - (1 * m + mean_sea_level), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + ground_level), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + ground_level) - (1 * m + tower_peak), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + mean_sea_level), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + mean_sea_level) - (1 * m + tower_peak), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + other_ground_level) - (1 * m + ground_level), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + ground_level) - (1 * m + other_ground_level), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + other_ground_level) - (1 * m + tower_peak), quantity<isq::height[m], int>>);
static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), quantity<isq::height[m], int>>);
// check for integral types promotion
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t{0} * m) + std::uint8_t{0} * m)
.quantity_from(mean_sea_level)
.numerical_value_in(m)),
int>);
static_assert(is_same_v<decltype((std::uint8_t{0} * m + (mean_sea_level + std::uint8_t{0} * m))
.quantity_from(mean_sea_level)
.numerical_value_in(m)),
int>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t{0} * m) - std::uint8_t{0} * m)
.quantity_from(mean_sea_level)
.numerical_value_in(m)),
int>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t{0} * m) - (mean_sea_level + std::uint8_t{0} * m))
.numerical_value_in(m)),
int>);
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<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1. * m + (mean_sea_level + 1 * m), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) + 1. * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1 * m + (mean_sea_level + 1. * km), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) + 1. * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1 * km + (mean_sea_level + 1. * m), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - 1. * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) - 1 * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) - 1 * km, quantity_point<si::metre, mean_sea_level, double>>);
// different units
static_assert(is_of_type<(mean_sea_level + 1 * m) + 1 * km, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<1 * m + (mean_sea_level + 1 * km), quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1. * m + (mean_sea_level + 1 * km), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) + 1. * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1 * m + (mean_sea_level + 1. * km), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) + 1. * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1. * m + (mean_sea_level + 1. * km), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) + 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<1 * km + (mean_sea_level + 1 * m), quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) + 1 * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1. * km + (mean_sea_level + 1 * m), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) + 1. * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1 * km + (mean_sea_level + 1. * m), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) + 1. * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<1. * km + (mean_sea_level + 1. * m), quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - 1 * km, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) - 1 * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - 1. * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) - 1. * km, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - 1 * m, quantity_point<si::metre, mean_sea_level, int>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) - 1 * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - 1. * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) - 1. * m, quantity_point<si::metre, mean_sea_level, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1 * km), quantity<si::metre, int>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) - (mean_sea_level + 1 * km), quantity<si::metre, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * m) - (mean_sea_level + 1. * km), quantity<si::metre, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * m) - (mean_sea_level + 1. * km), quantity<si::metre, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1 * m), quantity<si::metre, int>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1 * m), quantity<si::metre, double>>);
static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m), quantity<si::metre, double>>);
static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity<si::metre, double>>);
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<kind_of<isq::speed>> {
} 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<isq::speed[m / s], zero_m_per_s, int>>);
static_assert(is_of_type<10 * isq::height[m] / (2 * isq::time[s]) + (zero_m_per_s + 5 * isq::speed[m / s]),
quantity_point<isq::speed[m / s], zero_m_per_s, int>>);
static_assert(is_of_type<(zero_m_per_s + 5 * isq::speed[m / s]) + 10 * isq::height[m] / (2 * isq::time[s]),
quantity_point<isq::speed[m / s], zero_m_per_s, int>>);
static_assert(is_of_type<5 * isq::speed[m / s] + (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])),
quantity_point<isq::speed[m / s], zero_m_per_s, int>>);
static_assert(is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - 5 * isq::speed[m / s],
quantity_point<isq::speed[m / s], zero_m_per_s, int>>);
static_assert(is_of_type<(zero_m_per_s + 5 * isq::speed[m / s]) - 10 * isq::height[m] / (2 * isq::time[s]),
quantity_point<isq::speed[m / s], zero_m_per_s, int>>);
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<isq::speed[m / s], int>>);
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<isq::speed[m / s], int>>);
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<quantity_point{10 * isq::length[m] / (2 * isq::time[s])} + 5 * isq::speed[m / s],
quantity_point<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>>);
static_assert(is_of_type<10 * isq::height[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]},
quantity_point<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>>);
static_assert(is_of_type<quantity_point{5 * isq::speed[m / s]} + 10 * isq::height[m] / (2 * isq::time[s]),
quantity_point<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>>);
static_assert(is_of_type<5 * isq::speed[m / s] + quantity_point{10 * isq::length[m] / (2 * isq::time[s])},
quantity_point<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>>);
static_assert(is_of_type<quantity_point{10 * isq::length[m] / (2 * isq::time[s])} - 5 * isq::speed[m / s],
quantity_point<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>>);
static_assert(is_of_type<quantity_point{5 * isq::speed[m / s]} - 10 * isq::height[m] / (2 * isq::time[s]),
quantity_point<isq::speed[m / s], zeroth_point_origin<isq::speed>, int>>);
static_assert(
is_of_type<quantity_point{10 * isq::length[m] / (2 * isq::time[s])} - quantity_point{5 * isq::speed[m / s]},
quantity<isq::speed[m / s], int>>);
static_assert(
is_of_type<quantity_point{5 * isq::speed[m / s]} - quantity_point{10 * isq::length[m] / (2 * isq::time[s])},
quantity<isq::speed[m / s], int>>);
static_assert(
is_of_type<quantity_point{10 * isq::height[m] / (2 * isq::time[s])} + (10 * isq::height[m] / (2 * isq::time[s])),
quantity_point<(isq::height / isq::time)[m / s], zeroth_point_origin<isq::height / isq::time>, int>>);
inline constexpr struct zero_Hz final : absolute_point_origin<kind_of<isq::frequency>> {
} 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<isq::frequency[Hz], zero_Hz, int>>);
static_assert(is_of_type<10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz]),
quantity_point<isq::frequency[Hz], zero_Hz, int>>);
static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s]),
quantity_point<isq::frequency[Hz], zero_Hz, int>>);
static_assert(is_of_type<5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s])),
quantity_point<isq::frequency[Hz], zero_Hz, int>>);
static_assert(is_of_type<(zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz],
quantity_point<isq::frequency[Hz], zero_Hz, int>>);
static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s]),
quantity_point<isq::frequency[Hz], zero_Hz, int>>);
static_assert(is_of_type<(zero_Hz + 10 / (2 * isq::period_duration[s])) - (zero_Hz + 5 * isq::frequency[Hz]),
quantity<isq::frequency[Hz], int>>);
static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) - (zero_Hz + 10 / (2 * isq::period_duration[s])),
quantity<isq::frequency[Hz], int>>);
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<quantity_point{10 / (2 * isq::period_duration[s])} + 5 * isq::frequency[Hz],
quantity_point<isq::frequency[Hz], zeroth_point_origin<isq::frequency>, int>>);
static_assert(is_of_type<10 / (2 * isq::period_duration[s]) + quantity_point{5 * isq::frequency[Hz]},
quantity_point<isq::frequency[Hz], zeroth_point_origin<isq::frequency>, int>>);
static_assert(is_of_type<quantity_point{5 * isq::frequency[Hz]} + 10 / (2 * isq::period_duration[s]),
quantity_point<isq::frequency[Hz], zeroth_point_origin<isq::frequency>, int>>);
static_assert(is_of_type<5 * isq::frequency[Hz] + quantity_point{10 / (2 * isq::period_duration[s])},
quantity_point<isq::frequency[Hz], zeroth_point_origin<isq::frequency>, int>>);
static_assert(is_of_type<quantity_point{10 / (2 * isq::period_duration[s])} - 5 * isq::frequency[Hz],
quantity_point<isq::frequency[Hz], zeroth_point_origin<isq::frequency>, int>>);
static_assert(is_of_type<quantity_point{5 * isq::frequency[Hz]} - 10 / (2 * isq::period_duration[s]),
quantity_point<isq::frequency[Hz], zeroth_point_origin<isq::frequency>, int>>);
static_assert(is_of_type<quantity_point{10 / (2 * isq::period_duration[s])} - quantity_point{5 * isq::frequency[Hz]},
quantity<isq::frequency[Hz], int>>);
static_assert(is_of_type<quantity_point{5 * isq::frequency[Hz]} - quantity_point{10 / (2 * isq::period_duration[s])},
quantity<isq::frequency[Hz], int>>);
// Different named dimensions
template<typename... Ts>
consteval bool invalid_addition(Ts... ts)
{
return !requires { (... + ts); };
}
template<typename... Ts>
consteval bool invalid_subtraction(Ts... ts)
{
return !requires { (... - ts); };
}
inline constexpr struct zero_Bq final : absolute_point_origin<kind_of<isq::activity>> {
} 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<m>(quantity_point{2 * km}).quantity_from_zero().numerical_value_in(m) == 2000);
static_assert(value_cast<km>(quantity_point{2000 * m}).quantity_from_zero().numerical_value_in(km) == 2);
static_assert(value_cast<int>(quantity_point{1.23 * m}).quantity_from_zero().numerical_value_in(m) == 1);
static_assert(
value_cast<km / h>(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<m>(lvalue_qp).quantity_from_zero().numerical_value_in(m) == 2000);
static_assert(value_cast<float>(lvalue_qp).quantity_from_zero().numerical_value_in(km) == 2.f);
static_assert(value_cast<m, float>(lvalue_qp).quantity_from_zero().numerical_value_in(m) == 2000.f);
static_assert(value_cast<float, m>(lvalue_qp).quantity_from_zero().numerical_value_in(m) == 2000.f);
} // namespace lvalue_tests
static_assert(value_cast<quantity<km, int>>(quantity_point{2000 * m}).quantity_from_zero().numerical_value_in(km) == 2);
static_assert(value_cast<quantity_point<km>>(quantity_point{2000 * m}).quantity_from_zero().numerical_value_in(km) ==
2);
template<typename ToQ, typename FromQ>
constexpr bool value_cast_is_forbidden()
{
// it appears we cannot have the requires clause right inside static_assert
return !requires(FromQ q) { value_cast<ToQ>(q); };
}
static_assert(value_cast_is_forbidden<quantity_point<m>, quantity_point<isq::width[m]>>(),
"value_cast shall not cast between different quantity types");
static_assert(value_cast_is_forbidden<quantity_point<isq::width[m]>, quantity_point<m>>(),
"value_cast shall not cast between different quantity types");
// value_cast which does not touch the point_origin
static_assert(value_cast<quantity_point<isq::height[m]>>(quantity_point{2 * isq::height[km]})
.quantity_from_origin_is_an_implementation_detail_.numerical_value_in(m) == 2000);
static_assert(value_cast<quantity_point<isq::height[km]>>(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<isq::height[m], mean_sea_level>>(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<isq::height[m], mean_sea_level>>(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<isq::height[cm], mean_sea_level, int>>(
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<isq::height[mm], ground_level, std::int8_t>>(
quantity_point{4210 * isq::height[cm], mean_sea_level})
.quantity_from_origin_is_an_implementation_detail_.numerical_value_in(mm) == 100);
} // namespace