Files
mp-units/test/unit_test/static/quantity_kind_test.cpp
2021-03-19 06:47:37 +01:00

829 lines
51 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 "units/chrono.h"
#include "units/isq/si/cgs/speed.h"
#include "units/isq/si/area.h"
#include "units/isq/si/frequency.h"
#include "units/isq/si/speed.h"
#include "units/isq/si/fps/speed.h"
#include "units/quantity_point.h"
#include "units/quantity_kind.h"
#include <cassert>
#include <concepts>
#include <functional>
namespace {
using namespace units;
namespace si = isq::si;
using namespace si;
using namespace references;
constexpr auto cgs_cm = cgs::references::cm;
using namespace std::chrono_literals;
struct radius_kind : kind<radius_kind, dim_length> {};
struct width_kind : kind<width_kind, dim_length> {};
struct height_kind : kind<height_kind, dim_length> {};
struct horizontal_area_kind : derived_kind<horizontal_area_kind, width_kind, dim_area> {};
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, height_kind, dim_speed> {};
struct apple : kind<apple, dim_one> {};
struct orange : kind<orange, dim_one> {};
struct time_kind : kind<time_kind, dim_time> {};
struct cgs_width_kind : kind<cgs_width_kind, cgs::dim_length> {};
template <Unit U, QuantityValue Rep = double> using radius = quantity_kind<radius_kind, U, Rep>;
template <Unit U, QuantityValue Rep = double> using width = quantity_kind<width_kind, U, Rep>;
template <Unit U, QuantityValue Rep = double> using height = quantity_kind<height_kind, U, Rep>;
template <Unit U, QuantityValue Rep = double> using horizontal_area = quantity_kind<horizontal_area_kind, U, Rep>;
template <Unit U, QuantityValue Rep = double> using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
template <Unit U = one, QuantityValue Rep = double> using apples = quantity_kind<apple, U, Rep>;
template <Unit U = one, QuantityValue Rep = double> using oranges = quantity_kind<orange, U, Rep>;
template <Unit U, QuantityValue Rep = double> using cgs_width = quantity_kind<cgs_width_kind, U, Rep>;
/////////////
// concepts
/////////////
static_assert(QuantityKind<width<metre>>);
static_assert(QuantityKind<rate_of_climb<metre_per_second>>);
static_assert(!QuantityKind<double>);
static_assert(!QuantityKind<length<metre>>);
static_assert(!QuantityKind<quantity_point<dim_length, metre>>);
static_assert(QuantityKindOf<width<metre>, width_kind>);
static_assert(!QuantityKindOf<width<metre>, height_kind>);
static_assert(!QuantityKindOf<width<metre>, metre>);
static_assert(!QuantityKindOf<length<metre>, width_kind>);
static_assert(!QuantityKindOf<length<metre>, metre>);
static_assert(!QuantityKindOf<quantity_point<dim_length, metre>, width_kind>);
static_assert(!QuantityKindOf<quantity_point<dim_length, metre>, dim_length>);
static_assert(!QuantityKindOf<quantity_point<dim_length, metre>, metre>);
///////////////
// invariants
///////////////
static_assert(sizeof(width<metre, double>) == sizeof(double));
static_assert(sizeof(height<metre, short>) == sizeof(short));
template<typename Width>
concept invalid_types = requires {
requires !requires { typename quantity_kind<Width, second, int>; }; // unit of a different dimension
requires !requires { typename quantity_kind<Width, metre, length<metre>>; }; // quantity used as Rep
requires !requires { typename quantity_kind<Width, metre, quantity_point<dim_length, metre>>; }; // quantity point used as Rep
requires !requires { typename quantity_kind<Width, metre, width<metre>>; }; // quantity kind used as Rep
requires !requires { typename quantity_kind<metre, Width, double>; }; // reordered arguments
requires !requires { typename quantity_kind<metre, double, Width>; }; // reordered arguments
};
static_assert(invalid_types<width_kind>);
static_assert(std::is_trivially_default_constructible_v<width<metre>>);
static_assert(std::is_trivially_copy_constructible_v<width<metre>>);
static_assert(std::is_trivially_move_constructible_v<width<metre>>);
static_assert(std::is_trivially_copy_assignable_v<width<metre>>);
static_assert(std::is_trivially_move_assignable_v<width<metre>>);
static_assert(std::is_trivially_destructible_v<width<metre>>);
static_assert(std::is_nothrow_default_constructible_v<width<metre>>);
static_assert(std::is_nothrow_copy_constructible_v<width<metre>>);
static_assert(std::is_nothrow_move_constructible_v<width<metre>>);
static_assert(std::is_nothrow_copy_assignable_v<width<metre>>);
static_assert(std::is_nothrow_move_assignable_v<width<metre>>);
static_assert(std::is_nothrow_destructible_v<width<metre>>);
static_assert(std::is_trivially_copyable_v<width<metre>>);
static_assert(std::is_standard_layout_v<width<metre>>);
static_assert(std::default_initializable<width<metre>>);
static_assert(std::move_constructible<width<metre>>);
static_assert(std::copy_constructible<width<metre>>);
static_assert(std::equality_comparable<width<metre>>);
static_assert(std::totally_ordered<width<metre>>);
static_assert(std::regular<width<metre>>);
static_assert(std::three_way_comparable<width<metre>>);
static_assert(!std::is_aggregate_v<width<metre>>);
///////////////////
// member aliases
///////////////////
static_assert(is_same_v<width<metre>::kind_type, width_kind>);
static_assert(is_same_v<width<metre>::quantity_type, length<metre>>);
static_assert(is_same_v<width<metre>::dimension, dim_length>);
static_assert(is_same_v<width<metre>::unit, metre>);
static_assert(is_same_v<width<metre>::rep, double>);
////////////////////
// common observer
////////////////////
static_assert(same(radius<metre>{}.common(), length<metre>{}));
static_assert(radius<metre>{}.common() == // [VIM3] 1.2 kind of quantity
height<metre>{}.common()); // aspect common to mutually comparable quantities
// hence `.common()`
static_assert(!std::equality_comparable_with<apples<>, oranges<>>);
////////////////////////////
// static member functions
////////////////////////////
static_assert(width<metre, double>::zero().common() == 0 * m);
static_assert(width<metre, double>::one().common() == 1 * m);
static_assert(width<metre, unsigned>::min().common() == 0 * m);
static_assert(width<metre, unsigned>::max().common() == std::numeric_limits<unsigned>::max() * m);
static_assert(width<metre, double>::min().common().number() == std::numeric_limits<double>::lowest());
static_assert(width<metre, double>::max().common().number() == std::numeric_limits<double>::max());
////////////////////////
// default constructor
////////////////////////
// default initialization
#if !defined(UNITS_COMP_MSVC)
static_assert([] {
const auto read_uninitialized_quantity = [] {
width<metre> w;
++w;
};
return !require_constant_invocation<read_uninitialized_quantity>;
}());
#endif
// value initialization
static_assert(width<metre>{}.common() == 0 * m);
/////////
// CTAD
/////////
static_assert(same(quantity_kind(rate_of_climb<kilometre_per_hour, double>(0.01 * (km / h))),
rate_of_climb<kilometre_per_hour, double>(0.01 * (km / h))));
////////////////////////////
// construction from a rep
////////////////////////////
static_assert(construct_from_only<apples<one, int>>(1).common() == 1);
static_assert(construct_from_only<apples<one, double>>(1.0).common() == 1);
static_assert(construct_from_only<apples<percent, int>>(1ULL).common().number() == 1);
static_assert(construct_from_only<apples<percent, double>>(1.0L).common().number() == 1);
static_assert(!constructible_or_convertible_from<apples<one, int>>(1.0));
static_assert(!constructible_or_convertible_from<apples<percent, int>>(1.0));
static_assert(!constructible_or_convertible_from<width<metre, double>>(1.0));
static_assert(!constructible_or_convertible_from<width<metre, double>>(1.0f));
static_assert(!constructible_or_convertible_from<width<metre, float>>(1.0));
static_assert(!constructible_or_convertible_from<width<metre, double>>(1));
/////////////////////////////////
// construction from a quantity
/////////////////////////////////
static_assert(construct_from_only<width<metre, int>>(1 * m).common() == 1 * m);
static_assert(construct_from_only<width<metre, int>>(1 * km).common() == 1 * km);
// static_assert(construct_from_only<width<metre, int>>(1 * cgs_cm).common() == 1 * cm); // TODO: Fix #210
static_assert(construct_from_only<width<metre, double>>(1 * cgs_cm).common() == 1 * cm);
static_assert(construct_from_only<width<metre, double>>(1 * mm).common() == 1 * mm);
static_assert(construct_from_only<width<metre, double>>(1 * m).common() == 1 * m);
static_assert(construct_from_only<width<metre, double>>(1 * km).common() == 1 * km);
static_assert(construct_from_only<width<metre, double>>(1.0 * mm).common() == 1 * mm);
static_assert(construct_from_only<width<metre, double>>(1.0 * m).common() == 1 * m);
static_assert(construct_from_only<width<metre, double>>(1.0 * km).common() == 1 * km);
static_assert(construct_from_only<width<metre, float>>(1.0 * mm).common() == 1 * mm);
static_assert(construct_from_only<width<metre, float>>(1.0 * m).common() == 1 * m);
static_assert(construct_from_only<width<metre, float>>(1.0 * km).common() == 1 * km);
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * mm));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1.0 * mm));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1.0 * m));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1.0 * km));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * s));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * (m * m)));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * (m / s)));
static_assert(construct_from_only<width<metre, double>>(1.0f * m).common() == 1 * m);
static_assert(construct_from_only<width<metre, double>>(short{1} * m).common() == 1 * m);
static_assert(construct_from_only<width<metre, short>>(1 * m).common() == 1 * m);
static_assert(construct_from_only<apples<one, int>>(quantity(1)).common() == 1);
static_assert(construct_from_only<apples<one, double>>(dimensionless<percent>(1)).common() == 0.01);
static_assert(construct_from_only<apples<percent, double>>(quantity(1.0)).common().number() == 100);
static_assert(construct_from_only<apples<percent, double>>(dimensionless<percent>(1)).common().number() == 1);
static_assert(construct_from_only<apples<one, double>>(quantity(1.0)).common() == 1);
static_assert(construct_from_only<apples<one, double>>(quantity(1.0f)).common() == 1);
static_assert(construct_from_only<apples<one, float>>(quantity(1.0)).common() == 1);
static_assert(construct_from_only<apples<one, double>>(quantity(1)).common() == 1);
static_assert(construct_from_only<apples<one, double>>(quantity(short{1})).common() == 1);
static_assert(construct_from_only<apples<one, short>>(quantity(1)).common() == 1);
static_assert(construct_from_only<apples<percent, double>>(quantity(1.0)).common().number() == 1e2);
static_assert(construct_from_only<apples<percent, double>>(quantity(1.0f)).common().number() == 1e2);
static_assert(construct_from_only<apples<percent, float>>(quantity(1.0)).common().number() == 1e2f);
static_assert(construct_from_only<apples<percent, double>>(quantity(1)).common().number() == 1e2);
static_assert(construct_from_only<apples<percent, double>>(quantity(short{1})).common().number() == 1e2);
static_assert(construct_from_only<apples<percent, short>>(quantity(1)).common().number() == 1e2);
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<one, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<one, float>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, float>>(apples<one, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<one, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<one, short>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, short>>(apples<one, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<percent, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<percent, float>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, float>>(apples<percent, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<percent, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<percent, short>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, short>>(apples<percent, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<percent, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<percent, float>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, float>>(apples<percent, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<percent, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, double>>(apples<percent, short>{}));
static_assert(!constructible_or_convertible_from<dimensionless<one, short>>(apples<percent, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<one, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<one, float>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, float>>(apples<one, double>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<one, int>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, double>>(apples<one, short>{}));
static_assert(!constructible_or_convertible_from<dimensionless<percent, short>>(apples<one, int>{}));
static_assert(construct_from_only<quantity_kind<time_kind, second, int>>(42s).common() == 42 * s);
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * s));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * (m * m)));
static_assert(!constructible_or_convertible_from<width<metre, int>>(1 * (m / s)));
static_assert(construct_from_only<width<centimetre, double>>(1.0 * cgs_cm).common() == 1 * cm);
static_assert(construct_from_only<width<cgs::centimetre, double>>(1.0 * cm).common() == 1 * cm);
////////////////////////////////////////////
// construction from another quantity kind
////////////////////////////////////////////
// clang-format off
static_assert(construct_and_convert_from<width<metre, int>>(width<metre, int>(1 * m)).common() == 1 * m);
static_assert(construct_and_convert_from<width<centimetre, int>>(width<cgs::centimetre, int>(1 * cgs_cm)).common() == 1 * cm);
static_assert(construct_and_convert_from<width<fps::foot, double>>(width<cgs::centimetre, int>(1 * cgs_cm)).common() == 1 * cm);
// clang-format on
static_assert(construct_and_convert_from<width<metre, double>>(width<metre, int>(1 * m)).common() == 1 * m);
static_assert(!constructible_or_convertible_from<width<metre, int>>(width<metre, double>(1.0 * m)));
static_assert(construct_and_convert_from<width<metre, int>>(width<kilometre, int>(1 * km)).common() == 1 * km);
static_assert(!constructible_or_convertible_from<width<kilometre, int>>(width<metre, int>(1 * m)));
static_assert(construct_and_convert_from<width<metre, double>>(width<kilometre, int>(1 * km)).common() == 1 * km);
static_assert(construct_and_convert_from<width<kilometre, double>>(width<metre, int>(1 * m)).common() == 1 * m);
static_assert(!constructible_or_convertible_from<width<metre, int>>(height<metre, int>(1 * m)));
static_assert(!constructible_or_convertible_from<apples<one, int>>(width<metre, int>(1 * m) / (1 * m)));
static_assert(!constructible_or_convertible_from<apples<one, int>>(oranges<one, int>(1)));
//////////////////////////////////
// construction from other types
//////////////////////////////////
// clang-format off
static_assert(!constructible_or_convertible_from<width<metre, int>>(quantity_point(1 * m)));
static_assert(!constructible_or_convertible_from<width<metre, int>>(quantity_point(1 * km)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1 * m)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1 * km)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1.0 * m)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1.0 * km)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1.0 * (m * m))));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1.0 * s)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(quantity_point(1.0 * s)));
static_assert(!constructible_or_convertible_from<width<metre, double>>(1s));
static_assert(!constructible_or_convertible_from<width<metre, double>>(1.0s));
static_assert(!constructible_or_convertible_from<apples<one, int>>(quantity_point(1)));
static_assert(!constructible_or_convertible_from<apples<one, int>>(quantity_point(dimensionless<percent, int>(1))));
static_assert(!constructible_or_convertible_from<apples<one, double>>(quantity_point(1)));
static_assert(!constructible_or_convertible_from<apples<one, double>>(quantity_point(dimensionless<percent, int>(1))));
static_assert(!constructible_or_convertible_from<apples<one, double>>(quantity_point(1.0)));
static_assert(!constructible_or_convertible_from<apples<one, double>>(quantity_point(dimensionless<percent, double>(1.0))));
static_assert(!constructible_or_convertible_from<apples<one, double>>(quantity_point(1.0 * m)));
static_assert(!constructible_or_convertible_from<apples<one, double>>(1s));
static_assert(!constructible_or_convertible_from<apples<one, double>>(1.0s));
// clang-format on
////////////////////////
// assignment operator
////////////////////////
static_assert((width<metre, int>(2 * m) = width<metre, int>(1 * m)).common() == 1 * m);
static_assert((width<metre, int>(2 * m) = width<metre, int>(1 * km)).common() == 1 * km);
static_assert(!std::is_assignable_v<width<metre, int>, width<metre, double>>);
static_assert(!std::is_assignable_v<width<metre, int>, width<millimetre, int>>);
/////////////////////
// member operators
/////////////////////
#if !defined(UNITS_COMP_MSVC) || defined(NDEBUG)
static_assert([]() {
width<metre, int> w(1 * m);
assert(+w.common() == 1 * m);
assert(-w.common() == -1 * m);
assert(&++w == &w && w.common() == 2 * m);
assert(&--w == &w && w.common() == 1 * m);
assert((w++).common() == 1 * m && w.common() == 2 * m);
assert((w--).common() == 2 * m && w.common() == 1 * m);
assert(&(w += w) == &w && w.common() == 2 * m);
assert(&(w -= w) == &w && w.common() == 0 * m);
w = width<metre, int>(3 * m);
assert(&(w *= 3) == &w && w.common() == 9 * m);
assert(&(w *= quantity(1)) == &w && w.common() == 9 * m);
assert(&(w *= (w / w)) == &w && w.common() == 9 * m);
assert(&(w /= 2) == &w && w.common() == 4 * m);
assert(&(w /= quantity(1)) == &w && w.common() == 4 * m);
assert(&(w /= (w / w)) == &w && w.common() == 4 * m);
assert(&(w %= 3) == &w && w.common() == 1 * m);
assert(&(w %= quantity(3)) == &w && w.common() == 1 * m);
assert(&(w %= 3 * (w / w)) == &w && w.common() == 1 * m);
assert(&(w %= w) == &w && w.common() == 0 * m);
w = width<metre, int>(3 * m);
assert(&(w *= 3.9) == &w && w.common() == 11 * m);
assert(&(w *= quantity(1.0)) == &w && w.common() == 11 * m);
assert(&(w *= 1.0 * (w / w)) == &w && w.common() == 11 * m);
assert(&(w /= 3.9) == &w && w.common() == 2 * m);
assert(&(w /= quantity(1.0)) == &w && w.common() == 2 * m);
assert(&(w /= 1.0 * (w / w)) == &w && w.common() == 2 * m);
return true;
}());
#endif
static_assert((std::uint8_t(255) * m %= 256) == (width<metre, std::uint8_t>(255 * m) %= 256).common());
static_assert((std::uint8_t(255) * m %= quantity(256)) ==
(width<metre, std::uint8_t>(255 * m) %= quantity(256)).common());
// static_assert((std::uint8_t(255) * m %= 256 * m) ==
// (width<metre, std::uint8_t>(255 * m) %=
// quantity_kind<downcast_kind<width_kind, dim_one>, one, std::uint8_t>(256)).common()); // UB
// static_assert((std::uint8_t(255) * m %= 256 * m) !=
// (width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(256 * m)).common()); // UB
static_assert((std::uint8_t(255) * m %= 257) == (width<metre, std::uint8_t>(255 * m) %= 257).common());
static_assert((std::uint8_t(255) * m %= quantity(257)) ==
(width<metre, std::uint8_t>(255 * m) %= quantity(257)).common());
static_assert((std::uint8_t(255) * m %= 257 * m) ==
(width<metre, std::uint8_t>(255 * m) %=
quantity_kind<downcast_kind<width_kind, dim_one>, one, std::uint8_t>(257)).common());
static_assert((std::uint8_t(255) * m %= 257 * m) ==
(width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(257 * m)).common());
static_assert(same((-width<metre, short>(short{1} * m)).common(), int{-1} * m));
template<typename K, typename U, typename Qx>
concept invalid_compound_assignments_ = requires(quantity_kind<K, U, int> w, Qx q) {
requires !requires { w += q; };
requires !requires { w -= q; };
requires !requires { w *= q; };
requires !requires { w /= q; };
requires !requires { w %= q; };
};
template<typename Width>
concept invalid_compound_assignments = requires(quantity_kind<Width, metre, int> w, height<metre, int> h) {
requires !requires { w += 1; };
requires !requires { w -= 1; };
requires !requires { w *= 1 * (km / m); };
requires !requires { w /= 1 * (km / m); };
requires !requires { w %= 1 * (km / m); };
requires !requires { w += m; };
requires !requires { w -= m; };
requires !requires { w *= m; };
requires !requires { w /= m; };
requires !requires { w %= m; };
requires !requires { w *= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<ratio{1, 1, 3}, one>, int>{1}; };
requires !requires { w /= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<ratio{1, 1, 3}, one>, int>{1}; };
requires !requires { w %= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<ratio{1, 1, 3}, one>, int>{1}; };
requires !requires { w %= 1.0; };
requires !requires { w %= quantity(1.0); };
requires !requires { w %= 1.0 * (w / w); };
requires !requires { w %= 1.0 * w; };
requires !requires { w %= h / h; };
requires invalid_compound_assignments_<Width, metre, length<metre, int>>;
requires invalid_compound_assignments_<Width, metre, height<metre, int>>;
requires invalid_compound_assignments_<Width, metre, horizontal_area<square_metre, int>>;
requires invalid_compound_assignments_<Width, metre, quantity_point<dim_length, metre, int>>;
requires invalid_compound_assignments_<Width, metre, std::chrono::seconds>;
};
static_assert(invalid_compound_assignments<width_kind>);
static_assert(invalid_compound_assignments_<time_kind, second, std::chrono::seconds>);
/////////////////////////
// non-member operators
/////////////////////////
static_assert(same(width<metre, int>(2 * m) + width<metre, int>(3 * m), width<metre, int>(5 * m)));
static_assert(same(width<metre, int>(2 * m) + width<metre, double>(3. * m), width<metre, double>(5. * m)));
static_assert(same(width<metre, double>(2. * m) + width<metre, int>(3 * m), width<metre, double>(5. * m)));
static_assert(same(width<kilometre, int>(2 * km) + width<metre, double>(3e3 * m), width<metre, double>(5e3 * m)));
static_assert(same(width<metre, int>(2 * m) - width<metre, int>(3 * m), width<metre, int>(-1 * m)));
static_assert(same(width<metre, int>(2 * m) - width<metre, double>(3. * m), width<metre, double>(-1. * m)));
static_assert(same(width<metre, double>(2. * m) - width<metre, int>(3 * m), width<metre, double>(-1. * m)));
static_assert(same(width<metre, double>(2e3 * m) - width<kilometre, int>(3 * km), width<metre, double>(-1e3 * m)));
static_assert(is_same_v<
decltype((width<metre, std::uint8_t>(0 * m) + width<metre, std::uint8_t>(0 * m)).common().number()), int>);
static_assert(is_same_v<
decltype((width<metre, std::uint8_t>(0 * m) - width<metre, std::uint8_t>(0 * m)).common().number()), int>);
static_assert((width<metre, std::uint8_t>(128 * m) + width<metre, std::uint8_t>(128 * m)).common().number() ==
std::uint8_t(128) + std::uint8_t(128));
static_assert((width<metre, std::uint8_t>(0 * m) - width<metre, std::uint8_t>(1 * m)).common().number() ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, double>);
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, length<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, quantity_point<dim_length, metre>>);
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, reference<dim_length, metre>>);
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, double>);
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, length<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, quantity_point<dim_length, metre>>);
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, reference<dim_length, metre>>);
// clang-format off
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
// clang-format on
static_assert(same(width<metre, int>(2 * m) * 3, width<metre, int>(6 * m)));
static_assert(same(width<metre, int>(2 * m) * 3., width<metre, double>(6. * m)));
static_assert(same(width<metre, double>(2. * m) * 3, width<metre, double>(6. * m)));
static_assert(same(2 * width<metre, int>(3 * m), width<metre, int>(6 * m)));
static_assert(same(2 * width<metre, double>(3. * m), width<metre, double>(6. * m)));
static_assert(same(2. * width<metre, int>(3 * m), width<metre, double>(6. * m)));
static_assert(same(width<metre, int>(2 * m) * quantity(3), width<metre, int>(6 * m)));
static_assert(same(width<metre, int>(2 * m) * quantity(3.), width<metre, double>(6. * m)));
static_assert(same(width<metre, double>(2. * m) * quantity(3), width<metre, double>(6. * m)));
static_assert(same(quantity(2) * width<metre, int>(3 * m), width<metre, int>(6 * m)));
static_assert(same(quantity(2) * width<metre, double>(3. * m), width<metre, double>(6. * m)));
static_assert(same(quantity(2.) * width<metre, int>(3 * m), width<metre, double>(6. * m)));
static_assert(same(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
width<metre, int>(6 * m)));
static_assert(same(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3.),
width<metre, double>(6. * m)));
static_assert(same(width<metre, double>(2. * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
width<metre, double>(6. * m)));
static_assert(same(quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(2) * width<metre, int>(3 * m),
width<metre, int>(6 * m)));
static_assert(same(quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(2) * width<metre, double>(3. * m),
width<metre, double>(6. * m)));
static_assert(same(quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(2.) * width<metre, int>(3 * m),
width<metre, double>(6. * m)));
static_assert(same(height<metre, int>(2 * m) * (3 * Hz), rate_of_climb<metre_per_second, int>(6 * (m / s))));
static_assert(same(height<metre, int>(2 * m) * (3. * Hz), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(same(height<metre, double>(2. * m) * (3 * Hz), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(same((2 * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, int>(6 * (m / s))));
static_assert(same((2 * Hz) * height<metre, double>(3. * m), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(same((2. * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(same(quantity_kind<time_kind, second, int>(2 * s) * (3 * Hz),
quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(6)));
static_assert(same((3 * Hz) * quantity_kind<time_kind, second, int>(2 * s),
quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(6)));
static_assert(same(apples<one, int>(2) * quantity(2), apples<one, int>(4)));
static_assert(same(quantity(2) * apples<one, int>(2), apples<one, int>(4)));
// clang-format off
static_assert(same(width<metre, int>(4 * m) * (1 * m), horizontal_area<square_metre, int>(4 * (m * m))));
static_assert(same(width<metre, int>(2 * m) * width<metre, int>(2 * m), horizontal_area<square_metre, int>(4 * (m * m))));
static_assert(same(width<metre, int>(2 * m) * width<metre, double>(2 * m), horizontal_area<square_metre, double>(4 * (m * m))));
static_assert(same(width<metre, double>(2 * m) * width<metre, int>(2 * m), horizontal_area<square_metre, double>(4 * (m * m))));
// clang-format on
static_assert(same(apples<one, int>(2) * apples<one, int>(2), apples<one, int>(4)));
static_assert(same(apples<one, int>(2) * (2 / apples<one, int>(1)), apples<one, int>(4)));
static_assert(same(width<kilometre>(4 * m) * (1 * mm), horizontal_area<square_metre>(4 * (m * mm))));
static_assert(same(width<kilometre>(2 * m) * width<millimetre>(2 * m), horizontal_area<square_metre>(4 * (m * m))));
static_assert(same(width<metre>(2 * m) * (1 / width<metre>(2 * m)),
quantity_kind<downcast_kind<width_kind, dim_one>, one>(1)));
static_assert(same(width<metre, int>(2 * m) / 3, width<metre, int>(0 * m)));
static_assert(same(width<metre, int>(2 * m) / 3., width<metre, double>(2 / 3. * m)));
static_assert(same(width<metre, double>(2. * m) / 3, width<metre, double>(2. / 3 * m)));
static_assert(same(width<metre, int>(2 * m) / quantity(3), width<metre, int>(0 * m)));
static_assert(same(width<metre, int>(2 * m) / quantity(3.), width<metre, double>(2 / 3. * m)));
static_assert(same(width<metre, double>(2. * m) / quantity(3), width<metre, double>(2. / 3 * m)));
static_assert(same(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
width<metre, int>(0 * m)));
static_assert(same(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3.),
width<metre, double>(2 / 3. * m)));
static_assert(same(width<metre, double>(2. * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3),
width<metre, double>(2. / 3 * m)));
static_assert(same(2 / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
static_assert(same(2 / quantity_kind<time_kind, second, double>(3. * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(same(2. / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(same(quantity(2) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
static_assert(same(quantity(2) / quantity_kind<time_kind, second, double>(3. * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(same(quantity(2.) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
static_assert(
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) / quantity_kind<time_kind, second, double>(3. * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, double>(2.) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(same(height<metre, int>(2 * m) / (3 * s), rate_of_climb<metre_per_second, int>(0 * (m / s))));
static_assert(same(height<metre, int>(2 * m) / (3. * s), rate_of_climb<metre_per_second, double>(2 / 3. * (m / s))));
static_assert(same(height<metre, double>(2. * m) / (3 * s), rate_of_climb<metre_per_second, double>(2. / 3 * (m / s))));
static_assert(same(width<metre, int>(2 * m) * dimensionless<percent, int>(3), width<centimetre, int>(6 * cm)));
static_assert(same(dimensionless<percent, int>(2) * width<metre, int>(3 * m), width<centimetre, int>(6 * cm)));
static_assert(same(width<metre, int>(2 * m) / dimensionless<percent, double>(3), width<hectometre, double>(2. / 3 * hm)));
static_assert(same(width<metre, int>(2 * m) % dimensionless<percent, int>(3), width<centimetre, int>(2 * cm)));
static_assert(same(height<metre, int>(2 * m) / (3 * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
static_assert(same(height<metre, int>(2 * m) / (3. * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2 / 3.)));
static_assert(same(height<metre, double>(2. * m) / (3 * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2. / 3)));
static_assert(same((2 * m) / height<metre, int>(3 * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
static_assert(same((2 * m) / height<metre, double>(3. * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2 / 3.)));
static_assert(same((2. * m) / height<metre, int>(3 * m),
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2. / 3)));
static_assert(same(width<metre, int>(8 * m) / width<metre, int>(2 * m),
quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(4)));
static_assert(same(width<metre, int>(8 * m) / width<metre, double>(2 * m),
quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(4.0)));
static_assert(same(width<metre, double>(8 * m) / width<metre, int>(2 * m),
quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(4.0)));
static_assert(same(apples<one, int>(8) / apples<one, int>(2), apples<one, int>(4)));
static_assert(same(apples<one, int>(8) / (2 / apples<one, int>(1)), apples<one, int>(4)));
static_assert(same(horizontal_area<square_metre>(8 * (m * m)) / width<metre>(2 * m), width<metre>(4 * m)));
static_assert(same(horizontal_area<square_metre>(4 * (m * m)) / (1 * m), width<metre>(4 * m)));
static_assert(same(width<metre, int>(2 * m) % 3, width<metre, int>(2 * m)));
static_assert(same(width<metre, int>(3 * m) % width<metre, int>(2 * m), width<metre, int>(1 * m)));
static_assert(is_same_v<
decltype((width<metre, std::uint8_t>(0 * m) % width<metre, std::uint8_t>(0 * m)).common().number()),
decltype(std::uint8_t(0) % std::uint8_t(0))>);
static_assert(!std::is_invocable_v<std::multiplies<>, reference<dim_length, metre>, width<metre>>);
static_assert(!std::is_invocable_v<std::multiplies<>, width<metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::multiplies<>, height<metre>, quantity_point<dim_length, metre>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_point<dim_length, metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::divides<>, reference<dim_length, metre>, width<metre>>);
static_assert(!std::is_invocable_v<std::divides<>, width<metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::divides<>, height<metre>, quantity_point<dim_length, metre>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_point<dim_length, metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, reference<dim_length, metre>>);
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, length<metre, int>>);
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, quantity_point<dim_length, metre, int>>);
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, double>);
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, width<metre, double>>);
// clang-format off
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
// clang-format on
/////////////////////////
// comparison operators
/////////////////////////
static_assert(width<metre, int>(1 * m) == width<metre, int>(1 * m));
static_assert(width<metre, int>(1 * m) == width<metre, double>(1.0 * m));
static_assert(width<metre, int>(1 * m) == width<millimetre, int>(1000 * mm));
static_assert(width<metre, int>(1 * m) == width<millimetre, double>(1e3 * mm));
static_assert(width<metre, int>(2 * m) != width<metre, int>(1 * m));
static_assert(width<metre, int>(2 * m) != width<cgs::centimetre, double>(1.0 * cgs_cm));
static_assert(std::equality_comparable_with<width<metre, int>, width<metre, double>>);
static_assert(std::equality_comparable_with<width<nanometre, int>, width<kilometre, int>>);
static_assert(std::equality_comparable_with<width<cgs::centimetre, int>, width<millimetre, double>>);
static_assert(std::equality_comparable_with<width<metre>, width<cgs::centimetre>>);
template<typename Width>
concept invalid_equality = requires(quantity_kind<Width, metre, int> w) {
requires !requires { w == 1; };
requires !requires { w != 1.0; };
requires !requires { w == 1 * m; };
requires !requires { w != 1.0 * cgs_cm; };
requires !requires { w == 1 * km; };
requires !requires { w != m; };
requires !requires { w == km; };
requires !requires { w != quantity(1); };
requires !requires { w == dimensionless<percent>(1.0); };
requires !requires { w != height<metre, int>(1 * m); };
requires !requires { w == height<kilometre, double>(1.0 * km); };
requires !requires { w != horizontal_area<square_metre, int>(1 * (m * m)); };
requires !requires { w == rate_of_climb<kilometre_per_hour, double>(1.0 * (km / h)); };
requires !requires { w != quantity_point(1 * m); };
requires !requires { w == quantity_point(1.0 * mm); };
requires !requires { w != quantity_point(quantity(1)); };
requires !requires { w == quantity_point(dimensionless<percent>(1.0)); };
};
static_assert(invalid_equality<width_kind>);
static_assert(width<metre, int>(1 * m) < width<metre, int>(2 * m));
static_assert(width<metre, int>(1 * m) <= width<metre, double>(2.0 * m));
static_assert(width<metre, int>(1 * m) <= width<kilometre, int>(1 * km));
static_assert(width<metre, int>(1 * m) >= width<millimetre, double>(1e3 * mm));
static_assert(width<metre, int>(2 * m) >= width<millimetre, int>(1 * mm));
static_assert(width<metre, int>(2 * m) > width<cgs::centimetre, int>(1 * cgs_cm));
static_assert(std::three_way_comparable_with<width<metre, int>, width<metre, double>>);
static_assert(std::three_way_comparable_with<width<nanometre, int>, width<kilometre, int>>);
static_assert(std::three_way_comparable_with<width<cgs::centimetre, int>, width<millimetre, double>>);
static_assert(std::three_way_comparable_with<width<metre>, width<cgs::centimetre>>);
template<typename Width>
concept invalid_relational = requires(quantity_kind<Width, metre, int> w) {
requires !requires { w < 1; };
requires !requires { w <= 1.0; };
requires !requires { w >= 1 * m; };
requires !requires { w > 1.0 * cgs_cm; };
requires !requires { w <=> 1 * km; };
requires !requires { w < quantity(1); };
requires !requires { w <= dimensionless<percent>(1.0); };
requires !requires { w >= height<metre, int>(1 * m); };
requires !requires { w > height<kilometre, double>(1.0 * km); };
requires !requires { w <=> horizontal_area<square_metre, int>(1 * (m * m)); };
requires !requires { w < rate_of_climb<kilometre_per_hour, double>(1.0 * (km / h)); };
requires !requires { w <= quantity_point(1 * m); };
requires !requires { w >= quantity_point(1.0 * mm); };
requires !requires { w > quantity_point(quantity(1)); };
requires !requires { w <=> quantity_point(dimensionless<percent>(1.0)); };
};
static_assert(invalid_relational<width_kind>);
///////////////////////
// quantity_kind_cast
///////////////////////
// clang-format off
static_assert(same(quantity_kind_cast<width<metre, int>>(width<metre, int>(1 * m)), width<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<width<metre, double>>(width<metre, int>(1 * m)), width<metre, double>(1.0 * m)));
static_assert(same(quantity_kind_cast<width<kilometre, int>>(width<metre, int>(999 * m)), width<kilometre, int>(0 * km)));
static_assert(same(quantity_kind_cast<width<kilometre, int>>(width<metre, int>(1000 * m)), width<kilometre, int>(1 * km)));
static_assert(same(quantity_kind_cast<width<kilometre, double>>(width<metre, int>(999 * m)), width<kilometre, double>(0.999 * km)));
static_assert(same(quantity_kind_cast<double>(width<metre, int>(1 * m)), width<metre, double>(1.0 * m)));
static_assert(same(quantity_kind_cast<metre>(width<metre, int>(1 * m)), width<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<kilometre>(width<metre, int>(999 * m)), width<kilometre, int>(0 * km)));
static_assert(same(quantity_kind_cast<kilometre>(width<metre, int>(1000 * m)), width<kilometre, int>(1 * km)));
static_assert(same(quantity_kind_cast<height<metre, int>>(width<metre, int>(1 * m)), height<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<height<metre, double>>(width<metre, int>(1 * m)), height<metre, double>(1.0 * m)));
static_assert(same(quantity_kind_cast<height<kilometre, int>>(width<metre, int>(999 * m)), height<kilometre, int>(0 * km)));
static_assert(same(quantity_kind_cast<height<kilometre, int>>(width<metre, int>(1000 * m)), height<kilometre, int>(1 * km)));
static_assert(same(quantity_kind_cast<height<kilometre, double>>(width<metre, int>(999 * m)), height<kilometre, double>(0.999 * km)));
static_assert(same(quantity_kind_cast<height_kind>(width<metre, int>(1 * m)), height<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<height_kind, metre>(width<metre, int>(1 * m)), height<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<height_kind, kilometre>(width<metre, int>(999 * m)), height<kilometre, int>(0 * km)));
static_assert(same(quantity_kind_cast<height_kind, kilometre>(width<metre, int>(1000 * m)), height<kilometre, int>(1 * km)));
static_assert(same(quantity_kind_cast<cgs_width<cgs::centimetre, int>>(width<centimetre, int>(1 * cm)), cgs_width<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_kind_cast<cgs_width_kind>(width<centimetre, int>(1 * cm)), cgs_width<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_kind_cast<cgs_width_kind, cgs::centimetre>(width<centimetre, int>(1 * cm)), cgs_width<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_kind_cast<cgs_width_kind>(width<metre, int>(1 * m)), cgs_width<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<cgs_width_kind, metre>(width<metre, int>(1 * m)), cgs_width<metre, int>(1 * m)));
static_assert(same(quantity_kind_cast<cgs::dim_length>(width<centimetre, int>(1 * cm)), width<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_kind_cast<length<kilometre, int>>(width<metre, int>(1 * m)), width<kilometre, int>(0 * km)));
static_assert(same(quantity_kind_cast<length<centimetre, int>>(width<metre, int>(1 * m)), width<centimetre, int>(100 * cm)));
static_assert(same(quantity_kind_cast<length<centimetre, int>>(width<metre, double>(0.01 * m)), width<centimetre, int>(1 * cm)));
static_assert(same(quantity_kind_cast<length<centimetre, int>>(width<cgs::centimetre, int>(1 * cgs_cm)), width<cgs::centimetre, int>(1 * cgs_cm)));
// clang-format on
template<typename Width>
concept invalid_cast = requires {
requires !requires { quantity_kind_cast<apples<one, int>>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<horizontal_area<square_metre, int>>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<rate_of_climb<metre_per_second, int>>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<apple>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<horizontal_area_kind>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<rate_of_climb_kind>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<apple, one>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<horizontal_area_kind, square_metre>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<rate_of_climb_kind, metre_per_second>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<dimensionless<one>>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<square_metre>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<second>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<quantity_point<dim_length, metre, int>>(quantity_kind<Width, metre, int>(1 * m)); };
requires !requires { quantity_kind_cast<quantity_point<dim_one, one, int>>(quantity_kind<Width, metre, int>(1 * m)); };
};
static_assert(invalid_cast<width_kind>);
/////////////////////////
// extensible interface
/////////////////////////
namespace mylib {
struct radius_kind : kind<radius_kind, si::dim_length> {};
struct cylinder_size {};
template <units::QuantityKindOf<radius_kind> Radius, units::QuantityKindOf<height_kind> Height>
cylinder_size operator+(Radius, Height);
} // namespace mylib
namespace yourapp {
static_assert(is_same_v<mylib::cylinder_size,
decltype(quantity_kind<mylib::radius_kind, metre, double>(1. * m) + height<metre, double>(1. * m))>);
} // namespace yourapp
} // namespace