test: some more test suites removed

This commit is contained in:
Mateusz Pusz
2023-06-11 20:13:35 +03:00
parent 3887b642fb
commit 4d2ae79a05
5 changed files with 1 additions and 1882 deletions

View File

@@ -23,15 +23,11 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.2)
add_library(unit_tests_static_truncating quantity_test.cpp) add_library(unit_tests_static_truncating quantity_test.cpp)
# if(NOT ${projectPrefix}LIBCXX)
# target_sources(unit_tests_static_truncating PRIVATE quantity_kind_test.cpp quantity_point_kind_test.cpp)
# endif()
target_link_libraries(unit_tests_static_truncating PRIVATE mp-units::mp-units) target_link_libraries(unit_tests_static_truncating PRIVATE mp-units::mp-units)
target_compile_options( target_compile_options(
unit_tests_static_truncating PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,/wd4242 /wd4244,-Wno-conversion> unit_tests_static_truncating PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,/wd4242 /wd4244,-Wno-conversion>
) )
add_library( add_library(
unit_tests_static unit_tests_static
angular_test.cpp angular_test.cpp
@@ -49,7 +45,6 @@ add_library(
international_test.cpp international_test.cpp
isq_test.cpp isq_test.cpp
isq_angle_test.cpp isq_angle_test.cpp
# kind_test.cpp
# magnitude_test.cpp # magnitude_test.cpp
# math_test.cpp # math_test.cpp
natural_test.cpp natural_test.cpp

View File

@@ -1,206 +0,0 @@
// 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/bits/equivalent.h>
#include <units/bits/external/downcasting.h>
#include <units/bits/external/type_traits.h>
#include <units/generic/angle.h>
#include <units/isq/si/area.h>
#include <units/isq/si/length.h>
#include <units/isq/si/speed.h>
#include <units/kind.h>
#include <units/quantity_point.h>
#include <type_traits>
using namespace units;
using namespace isq::si;
namespace {
template<Downcastable T>
using downcast_result = std::conditional_t<UNITS_DOWNCAST_MODE != 0, T, units::downcast_base_t<T>>;
// no library-defined base kind
// spherical coordinates
struct radius : kind<radius, dim_length> {}; // program-defined base kind
struct colatitude : kind<colatitude, units::dim_angle<>> {};
struct azimuth : kind<azimuth, units::dim_angle<>> {};
static_assert(Kind<radius>);
static_assert(Kind<colatitude>);
static_assert(Kind<azimuth>);
static_assert(Kind<azimuth::kind>);
static_assert(Kind<azimuth::_kind_base>);
static_assert(!PointKind<radius>);
static_assert(!PointKind<colatitude>);
static_assert(!PointKind<azimuth>);
static_assert(!PointKind<azimuth::kind>);
static_assert(!PointKind<azimuth::_kind_base>);
static_assert(is_same_v<radius::base_kind, radius>);
static_assert(is_same_v<radius::dimension, dim_length>);
static_assert(compare<downcast_result<radius>, downcast_kind<radius, dim_length>>);
static_assert(equivalent<radius, radius>);
static_assert(equivalent<radius, radius::kind>);
static_assert(equivalent<radius, radius::_kind_base>);
static_assert(equivalent<radius::kind, radius::_kind_base>);
static_assert(equivalent<radius::_kind_base, radius::_kind_base>);
static_assert(!equivalent<radius, colatitude>);
static_assert(!equivalent<radius, azimuth>);
static_assert(!equivalent<azimuth, colatitude>);
static_assert(!equivalent<azimuth, colatitude::_kind_base>);
static_assert(!equivalent<azimuth::_kind_base, colatitude::_kind_base>);
static_assert(!equivalent<colatitude, downcast_kind<radius, dim_length>>);
static_assert(!equivalent<azimuth, downcast_kind<radius, dim_length>>);
using radial_area = downcast_kind<radius, dim_area>; // library-defined derived kind
using radial_point = downcast_point_kind<radius>; // library-defined base point kind
static_assert(Kind<radial_area>);
static_assert(!PointKind<radial_area>);
static_assert(is_same_v<radial_area::base_kind, radius>);
static_assert(is_same_v<radial_area::dimension, dim_area>);
static_assert(is_same_v<radial_area, detail::_kind_base<radius, dim_area>>);
static_assert(is_same_v<radial_area, downcast_kind<radius, dim_area>>);
static_assert(is_same_v<radial_area, downcast_kind<radial_area, dim_area>>);
static_assert(equivalent<radial_area, radial_area>);
static_assert(!equivalent<radial_area, radius>);
static_assert(!equivalent<radial_area, radius::_kind_base>);
static_assert(!Kind<radial_point>);
static_assert(PointKind<radial_point>);
static_assert(is_same_v<radial_point::base_kind, radius>);
static_assert(is_same_v<radial_point::dimension, dim_length>);
static_assert(is_same_v<radial_point, downcast_point_kind<radius>>);
static_assert(equivalent<radial_point, radial_point>);
static_assert(!equivalent<radial_point, radius>);
static_assert(!equivalent<radial_point, radius::_kind_base>);
static_assert(equivalent<radius, downcast_kind<radial_area, dim_length>>);
static_assert(!equivalent<radius, radial_area>);
static_assert(!equivalent<radius, radial_point>);
struct width : kind<width, units::isq::si::dim_length> {};
using horizontal_speed = downcast_kind<width, dim_speed>;
struct abscissa : point_kind<abscissa, width> {}; // program-defined base point kind
using horizontal_velocity = downcast_point_kind<downcast_kind<width, dim_speed>>; // library-defined derived point kind
static_assert(!Kind<abscissa>);
static_assert(!Kind<abscissa::point_kind>);
static_assert(!Kind<abscissa::_point_kind_base>);
static_assert(PointKind<abscissa>);
static_assert(PointKind<abscissa::point_kind>);
static_assert(PointKind<abscissa::_point_kind_base>);
static_assert(is_same_v<abscissa::base_kind, width>);
static_assert(is_same_v<abscissa::dimension, dim_length>);
static_assert(compare<downcast_result<abscissa>, downcast_point_kind<width>>);
static_assert(equivalent<abscissa, abscissa>);
static_assert(equivalent<abscissa, abscissa::point_kind>);
static_assert(equivalent<abscissa, abscissa::_point_kind_base>);
static_assert(!equivalent<abscissa, width>);
static_assert(!equivalent<abscissa, width::_kind_base>);
static_assert(!Kind<horizontal_velocity>);
static_assert(PointKind<horizontal_velocity>);
static_assert(is_same_v<horizontal_velocity::base_kind, horizontal_speed>);
static_assert(is_same_v<horizontal_velocity::dimension, dim_speed>);
static_assert(is_same_v<horizontal_velocity, downcast_point_kind<horizontal_speed>>);
static_assert(equivalent<horizontal_velocity, horizontal_velocity>);
static_assert(!equivalent<horizontal_velocity, horizontal_speed>);
static_assert(!equivalent<horizontal_velocity, width>);
static_assert(!equivalent<horizontal_velocity, width::_kind_base>);
static_assert(!equivalent<abscissa, horizontal_velocity>);
static_assert(!equivalent<abscissa::_point_kind_base, horizontal_velocity>);
struct height : kind<height, dim_length> {};
struct rate_of_climb : derived_kind<rate_of_climb, dim_speed, height> {}; // program-defined derived kind
struct velocity_of_climb : point_kind<velocity_of_climb, rate_of_climb> {}; // program-defined derived point kind
static_assert(Kind<rate_of_climb>);
static_assert(Kind<rate_of_climb::derived_kind>);
static_assert(Kind<rate_of_climb::_kind_base>);
static_assert(!PointKind<rate_of_climb>);
static_assert(!PointKind<rate_of_climb::derived_kind>);
static_assert(!PointKind<rate_of_climb::_kind_base>);
static_assert(is_same_v<rate_of_climb::base_kind, height>);
static_assert(is_same_v<rate_of_climb::dimension, dim_speed>);
static_assert(compare<downcast_result<rate_of_climb>, downcast_kind<rate_of_climb, dim_speed>>);
static_assert(compare<downcast_result<rate_of_climb>, downcast_kind<height, dim_speed>>);
static_assert(equivalent<rate_of_climb, rate_of_climb>);
static_assert(equivalent<rate_of_climb, rate_of_climb::derived_kind>);
static_assert(equivalent<rate_of_climb, rate_of_climb::_kind_base>);
static_assert(equivalent<rate_of_climb::derived_kind, rate_of_climb::_kind_base>);
static_assert(!equivalent<rate_of_climb, height>);
static_assert(!equivalent<rate_of_climb, height::_kind_base>);
static_assert(!Kind<velocity_of_climb>);
static_assert(!Kind<velocity_of_climb::point_kind>);
static_assert(!Kind<velocity_of_climb::_point_kind_base>);
static_assert(PointKind<velocity_of_climb>);
static_assert(PointKind<velocity_of_climb::point_kind>);
static_assert(PointKind<velocity_of_climb::_point_kind_base>);
static_assert(is_same_v<velocity_of_climb::base_kind, rate_of_climb>);
static_assert(is_same_v<velocity_of_climb::dimension, dim_speed>);
static_assert(compare<downcast_result<velocity_of_climb>, downcast_point_kind<rate_of_climb>>);
static_assert(equivalent<velocity_of_climb, velocity_of_climb>);
static_assert(equivalent<velocity_of_climb, velocity_of_climb::point_kind>);
static_assert(equivalent<velocity_of_climb, velocity_of_climb::_point_kind_base>);
static_assert(equivalent<velocity_of_climb::point_kind, velocity_of_climb::_point_kind_base>);
static_assert(equivalent<velocity_of_climb::_point_kind_base, velocity_of_climb::_point_kind_base>);
static_assert(!equivalent<height, rate_of_climb>);
static_assert(!equivalent<height, rate_of_climb::_kind_base>);
static_assert(!equivalent<height::_kind_base, rate_of_climb::_kind_base>);
static_assert(!equivalent<height, velocity_of_climb>);
static_assert(!equivalent<height, velocity_of_climb::_point_kind_base>);
static_assert(!equivalent<height::_kind_base, velocity_of_climb::_point_kind_base>);
static_assert(!equivalent<rate_of_climb, velocity_of_climb>);
static_assert(!equivalent<rate_of_climb::_kind_base, velocity_of_climb::_point_kind_base>);
static_assert(compare<downcast_result<height>, downcast_kind<rate_of_climb, dim_length>>);
} // namespace

View File

@@ -1,74 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <units/bits/equivalent.h>
#include <units/chrono.h>
#include <units/isq/si/cgs/length.h>
#include <units/isq/si/length.h>
#include <units/kind.h>
#include <units/quantity_point.h>
using namespace units;
namespace si = isq::si;
namespace {
struct width : kind<width, si::dim_length> {};
struct abscissa : point_kind<abscissa, width> {};
struct ones_viewpoint1 : point_origin<si::dim_length> {
template<typename D>
using rebind = ones_viewpoint1;
};
struct ones_viewpoint2 : point_origin<si::cgs::dim_length> {
template<typename D>
using rebind = ones_viewpoint1;
};
static_assert(PointOrigin<dynamic_origin<si::dim_length>>);
static_assert(!PointOrigin<point_origin<si::dim_length>>);
static_assert(!PointOrigin<width>);
static_assert(!PointOrigin<abscissa>);
static_assert(RebindablePointOriginFor<dynamic_origin<si::dim_length>, si::dim_length>);
static_assert(is_same_v<rebind_point_origin_dimension<dynamic_origin<si::dim_length>, si::dim_length>,
dynamic_origin<si::dim_length>>);
static_assert(RebindablePointOriginFor<dynamic_origin<si::dim_length>, si::dim_time>);
static_assert(
is_same_v<rebind_point_origin_dimension<dynamic_origin<si::dim_length>, si::dim_time>, dynamic_origin<si::dim_time>>);
static_assert(RebindablePointOriginFor<ones_viewpoint1, si::dim_length>);
static_assert(is_same_v<rebind_point_origin_dimension<ones_viewpoint1, si::dim_length>, ones_viewpoint1>);
static_assert(RebindablePointOriginFor<ones_viewpoint2, si::dim_length>);
static_assert(is_same_v<rebind_point_origin_dimension<ones_viewpoint2, si::dim_length>, ones_viewpoint1>);
static_assert(RebindablePointOriginFor<ones_viewpoint2, si::cgs::dim_length>);
static_assert(is_same_v<rebind_point_origin_dimension<ones_viewpoint2, si::cgs::dim_length>, ones_viewpoint2>);
static_assert(!RebindablePointOriginFor<ones_viewpoint1, si::cgs::dim_length>);
static_assert(equivalent<dynamic_origin<si::dim_time>, dynamic_origin<si::dim_time>>);
static_assert(equivalent<dynamic_origin<si::dim_length>, dynamic_origin<si::cgs::dim_length>>);
static_assert(!equivalent<dynamic_origin<si::dim_time>, clock_origin<std::chrono::system_clock>>);
static_assert(!equivalent<clock_origin<std::chrono::steady_clock>, clock_origin<std::chrono::system_clock>>);
static_assert(!equivalent<dynamic_origin<si::dim_time>, dynamic_origin<si::dim_length>>);
static_assert(!equivalent<ones_viewpoint1, ones_viewpoint2>);
} // namespace

View File

@@ -1,869 +0,0 @@
// 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/bits/external/type_traits.h>
#include <units/chrono.h>
#include <units/generic/dimensionless.h>
#include <units/isq/si/area.h>
#include <units/isq/si/cgs/length.h>
#include <units/isq/si/fps/length.h>
#include <units/isq/si/frequency.h>
#include <units/isq/si/speed.h>
#include <units/quantity_kind.h>
#include <units/quantity_point.h>
#include <units/unit.h>
#include <cassert>
#include <functional>
#include <limits>
#include <type_traits>
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, dim_area, width_kind> {};
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, dim_speed, height_kind> {};
struct apple : kind<apple, dimension_one> {};
struct orange : kind<orange, dimension_one> {};
struct time_kind : kind<time_kind, dim_time> {};
struct cgs_width_kind : kind<cgs_width_kind, cgs::dim_length> {};
template<Unit U, Representation Rep = double>
using radius = quantity_kind<radius_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using width = quantity_kind<width_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using height = quantity_kind<height_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using horizontal_area = quantity_kind<horizontal_area_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
template<Unit U = one, Representation Rep = double>
using apples = quantity_kind<apple, U, Rep>;
template<Unit U = one, Representation Rep = double>
using oranges = quantity_kind<orange, U, Rep>;
template<Unit U, Representation 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<dynamic_origin<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<dynamic_origin<dim_length>, metre>, width_kind>);
static_assert(!QuantityKindOf<quantity_point<dynamic_origin<dim_length>, metre>, dim_length>);
static_assert(!QuantityKindOf<quantity_point<dynamic_origin<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 { // quantity point used as Rep
typename quantity_kind<Width, metre, quantity_point<dynamic_origin<dim_length>, metre>>;
};
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>>(1LL).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, dimension_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, dimension_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, dimension_one>, scaled_unit<mag<1000>(), one>, int>{1};
};
requires !requires {
w /= quantity_kind<downcast_kind<Width, dimension_one>, scaled_unit<mag<1000>(), one>, int>{1};
};
requires !requires {
w %= quantity_kind<downcast_kind<Width, dimension_one>, scaled_unit<mag<1000>(), 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<dynamic_origin<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(comp(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(comp(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<dynamic_origin<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<dynamic_origin<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, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dimension_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, dimension_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, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dimension_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, dimension_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(comp(width<metre, int>(2 * m) * quantity(3), width<metre, int>(6 * m)));
static_assert(comp(width<metre, int>(2 * m) * quantity(3.), width<metre, double>(6. * m)));
static_assert(comp(width<metre, double>(2. * m) * quantity(3), width<metre, double>(6. * m)));
static_assert(comp(quantity(2) * width<metre, int>(3 * m), width<metre, int>(6 * m)));
static_assert(comp(quantity(2) * width<metre, double>(3. * m), width<metre, double>(6. * m)));
static_assert(comp(quantity(2.) * width<metre, int>(3 * m), width<metre, double>(6. * m)));
static_assert(comp(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(3),
width<metre, int>(6 * m)));
static_assert(comp(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(3.),
width<metre, double>(6. * m)));
static_assert(comp(width<metre, double>(2. * m) * quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(3),
width<metre, double>(6. * m)));
static_assert(comp(quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(2) * width<metre, int>(3 * m),
width<metre, int>(6 * m)));
static_assert(comp(quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(2) * width<metre, double>(3. * m),
width<metre, double>(6. * m)));
static_assert(comp(quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(2.) * width<metre, int>(3 * m),
width<metre, double>(6. * m)));
static_assert(comp(height<metre, int>(2 * m) * (3 * Hz), rate_of_climb<metre_per_second, int>(6 * (m / s))));
static_assert(comp(height<metre, int>(2 * m) * (3. * Hz), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(comp(height<metre, double>(2. * m) * (3 * Hz), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(comp((2 * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, int>(6 * (m / s))));
static_assert(comp((2 * Hz) * height<metre, double>(3. * m), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(comp((2. * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, double>(6. * (m / s))));
static_assert(comp(quantity_kind<time_kind, second, int>(2 * s) * (3 * Hz),
quantity_kind<downcast_kind<time_kind, dimension_one>, one, int>(6)));
static_assert(comp((3 * Hz) * quantity_kind<time_kind, second, int>(2 * s),
quantity_kind<downcast_kind<time_kind, dimension_one>, one, int>(6)));
static_assert(comp(apples<one, int>(2) * quantity(2), apples<one, int>(4)));
static_assert(comp(quantity(2) * apples<one, int>(2), apples<one, int>(4)));
// clang-format off
static_assert(comp(width<metre, int>(4 * m) * (1 * m), horizontal_area<square_metre, int>(4 * (m * m))));
static_assert(comp(width<metre, int>(2 * m) * width<metre, int>(2 * m), horizontal_area<square_metre, int>(4 * (m * m))));
static_assert(comp(width<metre, int>(2 * m) * width<metre, double>(2 * m), horizontal_area<square_metre, double>(4 * (m * m))));
static_assert(comp(width<metre, double>(2 * m) * width<metre, int>(2 * m), horizontal_area<square_metre, double>(4 * (m * m))));
// clang-format on
static_assert(comp(apples<one, int>(2) * apples<one, int>(2), apples<one, int>(4)));
static_assert(comp(apples<one, int>(2) * (2 / apples<one, int>(1)), apples<one, int>(4)));
static_assert(comp(width<kilometre>(4 * m) * (1 * mm), horizontal_area<square_metre>(4 * (m * mm))));
static_assert(comp(width<kilometre>(2 * m) * width<millimetre>(2 * m), horizontal_area<square_metre>(4 * (m * m))));
static_assert(comp(width<metre>(2 * m) * (1 / width<metre>(2 * m)),
quantity_kind<downcast_kind<width_kind, dimension_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(comp(width<metre, int>(2 * m) / quantity(3), width<metre, int>(0 * m)));
static_assert(comp(width<metre, int>(2 * m) / quantity(3.), width<metre, double>(2 / 3. * m)));
static_assert(comp(width<metre, double>(2. * m) / quantity(3), width<metre, double>(2. / 3 * m)));
static_assert(comp(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(3),
width<metre, int>(0 * m)));
static_assert(comp(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(3.),
width<metre, double>(2 / 3. * m)));
static_assert(comp(width<metre, double>(2. * m) /
quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(3),
width<metre, double>(2. / 3 * m)));
static_assert(comp(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(comp(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(comp(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(comp(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(comp(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(comp(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(comp(quantity_kind<downcast_kind<time_kind, dimension_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(comp(quantity_kind<downcast_kind<time_kind, dimension_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(comp(quantity_kind<downcast_kind<time_kind, dimension_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(comp(height<metre, int>(2 * m) / (3 * s), rate_of_climb<metre_per_second, int>(0 * (m / s))));
static_assert(comp(height<metre, int>(2 * m) / (3. * s), rate_of_climb<metre_per_second, double>(2 / 3. * (m / s))));
static_assert(comp(height<metre, double>(2. * m) / (3 * s), rate_of_climb<metre_per_second, double>(2. / 3 * (m / s))));
static_assert(comp(width<metre, int>(2 * m) * dimensionless<percent, int>(3), width<centimetre, int>(6 * cm)));
static_assert(comp(dimensionless<percent, int>(2) * width<metre, int>(3 * m), width<centimetre, int>(6 * cm)));
static_assert(comp(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<metre, int>(2 * m)));
static_assert(comp(height<metre, int>(2 * m) / (3 * m),
quantity_kind<downcast_kind<height_kind, dimension_one>, one, int>(0)));
static_assert(comp(height<metre, int>(2 * m) / (3. * m),
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2 / 3.)));
static_assert(comp(height<metre, double>(2. * m) / (3 * m),
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2. / 3)));
static_assert(comp((2 * m) / height<metre, int>(3 * m),
quantity_kind<downcast_kind<height_kind, dimension_one>, one, int>(0)));
static_assert(comp((2 * m) / height<metre, double>(3. * m),
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2 / 3.)));
static_assert(comp((2. * m) / height<metre, int>(3 * m),
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2. / 3)));
static_assert(comp(width<metre, int>(8 * m) / width<metre, int>(2 * m),
quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(4)));
static_assert(comp(width<metre, int>(8 * m) / width<metre, double>(2 * m),
quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(4.0)));
static_assert(comp(width<metre, double>(8 * m) / width<metre, int>(2 * m),
quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(4.0)));
static_assert(comp(apples<one, int>(8) / apples<one, int>(2), apples<one, int>(4)));
static_assert(comp(apples<one, int>(8) / (2 / apples<one, int>(1)), apples<one, int>(4)));
static_assert(comp(horizontal_area<square_metre>(8 * (m * m)) / width<metre>(2 * m), width<metre>(4 * m)));
static_assert(comp(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<dynamic_origin<dim_length>, metre>>);
static_assert(
!std::is_invocable_v<std::multiplies<>, quantity_point<dynamic_origin<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<dynamic_origin<dim_length>, metre>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_point<dynamic_origin<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<dynamic_origin<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, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dimension_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, dimension_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, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dimension_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, dimension_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, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dimension_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, dimension_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(comp(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<dynamic_origin<dim_length>, metre, int>>(quantity_kind<Width, metre, int>(1 * m));
};
requires !requires {
quantity_kind_cast<quantity_point<dynamic_origin<dimension_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

View File

@@ -1,727 +0,0 @@
// 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/bits/external/type_traits.h>
#include <units/chrono.h>
#include <units/generic/dimensionless.h>
#include <units/isq/si/area.h>
#include <units/isq/si/cgs/length.h>
#include <units/isq/si/fps/length.h>
#include <units/isq/si/speed.h>
#include <units/quantity_point_kind.h>
#include <cassert>
#include <functional>
#include <limits>
#include <type_traits>
namespace {
using namespace units;
namespace si = isq::si;
using namespace si;
using namespace references;
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
constexpr auto cgs_cm = cgs::references::cm;
using namespace std::chrono_literals;
struct width_kind : kind<width_kind, dim_length> {};
struct height_kind : kind<height_kind, dim_length> {};
struct abscissa_kind : point_kind<abscissa_kind, width_kind> {};
struct ordinate_kind : point_kind<ordinate_kind, height_kind> {};
struct distance_kind : kind<distance_kind, dim_length> {};
struct cgs_width_kind : kind<cgs_width_kind, cgs::dim_length> {};
struct cgs_height_kind : kind<cgs_height_kind, cgs::dim_length> {};
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, dim_speed, height_kind> {};
struct altitude_kind : point_kind<altitude_kind, cgs_height_kind> {};
struct sea_level_origin : point_origin<dim_length> {};
struct sea_level_altitude_kind : point_kind<sea_level_altitude_kind, height_kind, sea_level_origin> {};
template<Dimension D>
struct screen_origin : point_origin<D> {
template<Dimension D2>
using rebind = screen_origin<D2>;
};
struct screen_si_width_kind : point_kind<screen_si_width_kind, width_kind, screen_origin<dim_length>> {};
struct screen_si_cgs_width_kind :
point_kind<screen_si_cgs_width_kind, cgs_width_kind, screen_origin<cgs::dim_length>> {};
struct apple : kind<apple, dim_one> {};
struct orange : kind<orange, dim_one> {};
struct nth_apple_kind : point_kind<nth_apple_kind, apple> {};
struct nth_orange_kind : point_kind<nth_orange_kind, orange> {};
struct time_kind : kind<time_kind, dim_time> {};
struct time_point_kind : point_kind<time_point_kind, time_kind> {};
struct sys_time_point_kind : point_kind<time_point_kind, time_kind, clock_origin<std::chrono::system_clock>> {};
template<Unit U, Representation Rep = double>
using width = quantity_kind<width_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using height = quantity_kind<height_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using abscissa = quantity_point_kind<abscissa_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using ordinate = quantity_point_kind<ordinate_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using distance = quantity_kind<distance_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using cgs_width = quantity_kind<cgs_width_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using cgs_height = quantity_kind<cgs_height_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using altitude = quantity_point_kind<altitude_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using sea_level_altitude = quantity_point_kind<sea_level_altitude_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using screen_si_width = quantity_point_kind<screen_si_width_kind, U, Rep>;
template<Unit U, Representation Rep = double>
using screen_si_cgs_width = quantity_point_kind<screen_si_cgs_width_kind, U, Rep>;
template<Unit U = one, Representation Rep = double>
using apples = quantity_kind<apple, U, Rep>;
template<Unit U = one, Representation Rep = double>
using oranges = quantity_kind<orange, U, Rep>;
template<Unit U = one, Representation Rep = double>
using nth_apple = quantity_point_kind<nth_apple_kind, U, Rep>;
template<Unit U = one, Representation Rep = double>
using nth_orange = quantity_point_kind<nth_orange_kind, U, Rep>;
/////////////
// concepts
/////////////
static_assert(QuantityPointKind<abscissa<metre>>);
static_assert(QuantityPointKind<nth_apple<one>>);
static_assert(!QuantityPointKind<double>);
static_assert(!QuantityPointKind<length<metre>>);
static_assert(!QuantityPointKind<quantity_point<dynamic_origin<dim_length>, metre>>);
static_assert(!QuantityPointKind<width<metre>>);
static_assert(QuantityPointKindOf<abscissa<metre>, abscissa_kind>);
static_assert(!QuantityPointKindOf<abscissa<metre>, ordinate_kind>);
static_assert(!QuantityPointKindOf<abscissa<metre>, metre>);
static_assert(!QuantityPointKindOf<length<metre>, abscissa_kind>);
static_assert(!QuantityPointKindOf<length<metre>, metre>);
static_assert(!QuantityPointKindOf<width<metre>, abscissa_kind>);
static_assert(!QuantityPointKindOf<width<metre>, width_kind>);
static_assert(!QuantityPointKindOf<width<metre>, metre>);
static_assert(!QuantityPointKindOf<abscissa<metre>, sea_level_altitude_kind>);
static_assert(!QuantityPointKindOf<altitude<metre>, sea_level_altitude_kind>);
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, width_kind>);
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, dim_length>);
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, dynamic_origin<dim_length>>);
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, metre>);
///////////////
// invariants
///////////////
static_assert(sizeof(abscissa<metre, double>) == sizeof(double));
static_assert(sizeof(ordinate<metre, short>) == sizeof(short));
template<typename Width, typename Abscissa>
concept invalid_types = requires {
requires !requires { typename quantity_point_kind<Width, metre, int>; }; // width_kind is not a point kind
requires !requires { typename quantity_point_kind<Abscissa, second, int>; }; // unit of a different dimension
requires !requires { typename quantity_point_kind<Abscissa, metre, length<metre>>; }; // quantity used as Rep
requires !requires {
typename quantity_point_kind<Abscissa, metre, quantity_point<dynamic_origin<dim_length>, metre>>;
}; // quantity point used as Rep
requires !requires { typename quantity_point_kind<Abscissa, metre, width<metre>>; }; // quantity kind used as Rep
requires !requires {
typename quantity_point_kind<Abscissa, metre, abscissa<metre>>;
}; // quantity point kind used as Rep
requires !requires { typename quantity_point_kind<metre, Abscissa, double>; }; // reordered arguments
requires !requires { typename quantity_point_kind<metre, double, Abscissa>; }; // reordered arguments
};
static_assert(invalid_types<width_kind, abscissa_kind>);
static_assert(std::is_trivially_default_constructible_v<abscissa<metre>>);
static_assert(std::is_trivially_copy_constructible_v<abscissa<metre>>);
static_assert(std::is_trivially_move_constructible_v<abscissa<metre>>);
static_assert(std::is_trivially_copy_assignable_v<abscissa<metre>>);
static_assert(std::is_trivially_move_assignable_v<abscissa<metre>>);
static_assert(std::is_trivially_destructible_v<abscissa<metre>>);
static_assert(std::is_nothrow_default_constructible_v<abscissa<metre>>);
static_assert(std::is_nothrow_copy_constructible_v<abscissa<metre>>);
static_assert(std::is_nothrow_move_constructible_v<abscissa<metre>>);
static_assert(std::is_nothrow_copy_assignable_v<abscissa<metre>>);
static_assert(std::is_nothrow_move_assignable_v<abscissa<metre>>);
static_assert(std::is_nothrow_destructible_v<abscissa<metre>>);
static_assert(std::is_trivially_copyable_v<abscissa<metre>>);
static_assert(std::is_standard_layout_v<abscissa<metre>>);
static_assert(std::default_initializable<abscissa<metre>>);
static_assert(std::move_constructible<abscissa<metre>>);
static_assert(std::copy_constructible<abscissa<metre>>);
static_assert(std::equality_comparable<abscissa<metre>>);
static_assert(std::totally_ordered<abscissa<metre>>);
static_assert(std::regular<abscissa<metre>>);
static_assert(std::three_way_comparable<abscissa<metre>>);
static_assert(!std::is_aggregate_v<abscissa<metre>>);
///////////////////
// member aliases
///////////////////
static_assert(is_same_v<abscissa<metre>::point_kind_type, abscissa_kind>);
static_assert(is_same_v<abscissa<metre>::kind_type, width_kind>);
static_assert(is_same_v<abscissa<metre>::origin, dynamic_origin<dim_length>>);
static_assert(is_same_v<abscissa<metre>::quantity_kind_type, width<metre>>);
static_assert(is_same_v<abscissa<metre>::quantity_type, length<metre>>);
static_assert(is_same_v<abscissa<metre>::dimension, dim_length>);
static_assert(is_same_v<abscissa<metre>::unit, metre>);
static_assert(is_same_v<abscissa<metre>::rep, double>);
//////////////////////
// relative observer
//////////////////////
static_assert(same(abscissa<metre>{}.relative(), width<metre>{}));
////////////////////////////
// static member functions
////////////////////////////
static_assert(abscissa<metre, unsigned>::min().relative().common() == 0 * m);
static_assert(abscissa<metre, unsigned>::max().relative().common() == std::numeric_limits<unsigned>::max() * m);
static_assert(abscissa<metre, double>::min().relative().common().number() == std::numeric_limits<double>::lowest());
static_assert(abscissa<metre, double>::max().relative().common().number() == std::numeric_limits<double>::max());
////////////////////////
// default constructor
////////////////////////
// default initialization
#if !defined(UNITS_COMP_MSVC)
static_assert([] {
const auto read_uninitialized_quantity = [] {
abscissa<metre> w;
++w;
};
return !require_constant_invocation<read_uninitialized_quantity>;
}());
#endif
// value initialization
static_assert(abscissa<metre>{}.relative().common() == 0 * m);
/////////
// CTAD
/////////
static_assert(comp(quantity_point_kind(width<metre, int>(0 * m)), abscissa<metre, int>{}));
static_assert(same(quantity_point_kind(abscissa<metre, int>(0 * m)), abscissa<metre, int>{}));
////////////////////////////
// construction from a rep
////////////////////////////
static_assert(construct_from_only<nth_apple<one, double>>(1.0).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(1.0f).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(1).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(short{1}).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, short>>(1).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, int>>(1).relative().common() == 1);
static_assert(construct_from_only<nth_apple<percent, int>>(1LL).relative().common().number() == 1);
static_assert(construct_from_only<nth_apple<percent, double>>(1).relative().common().number() == 1);
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(1.0));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(1.0));
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(1.0));
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(1.0f));
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(1));
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(short{1}));
static_assert(!constructible_or_convertible_from<abscissa<metre, short>>(1));
/////////////////////////////////
// construction from a quantity
/////////////////////////////////
// clang-format off
static_assert(construct_from_only<abscissa<metre, short>>(1 * m).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, int>>(1 * m).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, int>>(1 * km).relative().common() == 1 * km);
static_assert(construct_from_only<abscissa<metre, int>>(1ULL * m).relative().common() == 1 * m);
// static_assert(construct_from_only<abscissa<metre, int>>(1 * cgs_cm).relative().common() == 1 * cm); // TODO: Fix #210
static_assert(construct_from_only<abscissa<metre, double>>(1 * m).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, double>>(1.0 * km).relative().common() == 1 * km);
static_assert(construct_from_only<abscissa<metre, double>>(1 * cgs_cm).relative().common() == 1 * cm);
static_assert(construct_from_only<abscissa<metre, double>>(1.0 * cgs_cm).relative().common() == 1 * cm);
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(1 * mm));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(1.0 * m));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(1.0 * km));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(1 * cgs_cm));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(quantity(1)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(1 * s));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(1s));
static_assert(construct_from_only<nth_apple<one, int>>(quantity(1)).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(dimensionless<percent>(1)).relative().common() == 0.01);
static_assert(construct_from_only<nth_apple<one, double>>(dimensionless<percent>(1)).relative().common() == 0.01);
static_assert(construct_from_only<nth_apple<percent, double>>(dimensionless<percent>(1)).relative().common().number() == 1);
static_assert(construct_from_only<nth_apple<percent, double>>(quantity(1)).relative().common().number() == 100);
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(quantity(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(dimensionless<percent>(1)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(quantity(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(dimensionless<percent>(1)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(1 * m));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(1 * s));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(1s));
// clang-format on
///////////////////////////////////////
// construction from a quantity point
///////////////////////////////////////
static_assert(construct_from_only<abscissa<metre, short>>(1 * m).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, int>>(quantity_point(short{1} * m)).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, int>>(quantity_point(1 * m)).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, int>>(quantity_point(1 * km)).relative().common() == 1 * km);
static_assert(construct_from_only<abscissa<metre, double>>(quantity_point(1 * m)).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, double>>(quantity_point(1 * km)).relative().common() == 1 * km);
static_assert(construct_from_only<abscissa<metre, double>>(quantity_point(1.0 * m)).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, double>>(quantity_point(1.0 * mm)).relative().common() == 1 * mm);
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(quantity_point(1 * mm)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(quantity_point(1.0 * m)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(quantity_point(1.0 * km)));
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(quantity_point(1.0 * (m * m))));
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(quantity_point(1.0 * s)));
static_assert(construct_from_only<screen_si_width<metre>>(quantity_point<screen_origin<dim_length>, metre>(1 * m))
.relative()
.common() == 1 * m);
static_assert(construct_from_only<screen_si_width<metre>>(quantity_point<screen_origin<cgs::dim_length>, metre>(1 * m))
.relative()
.common() == 1 * m);
static_assert(!constructible_or_convertible_from<sea_level_altitude<metre, double>>(quantity_point(1.0 * m)));
// clang-format off
static_assert(construct_from_only<nth_apple<one, short>>(quantity_point(1)).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, int>>(quantity_point(1)).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(quantity_point(1)).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(quantity_point(dimensionless<percent, int>(1))).relative().common() == 0.01);
static_assert(construct_from_only<nth_apple<one, double>>(quantity_point(1.0)).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(quantity_point(dimensionless<percent, double>(1.0))).relative().common() == 0.01);
static_assert(construct_from_only<nth_apple<percent, int>>(quantity_point(1)).relative().common().number() == 100);
static_assert(construct_from_only<nth_apple<percent, double>>(quantity_point(dimensionless<percent>(1))).relative().common().number() == 1);
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(quantity_point(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(quantity_point(dimensionless<percent>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(quantity_point(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(quantity_point(dimensionless<percent, int>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(quantity_point(dimensionless<percent, double>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, double>>(quantity_point(1.0 * s)));
// clang-format on
static_assert(
construct_from_only<quantity_point_kind<sys_time_point_kind, second, int>>(sys_seconds{42s}).relative().common() ==
42 * s);
static_assert(!constructible_or_convertible_from<quantity_point_kind<time_point_kind, second, int>>(sys_seconds{42s}),
"no implicit conversion to/from dynamic_origin");
//////////////////////////////////////
// construction from a quantity kind
//////////////////////////////////////
// clang-format off
static_assert(construct_from_only<abscissa<metre, int>>(width<metre, int>(1 * m)).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, int>>(width<kilometre, unsigned long long>(1ULL * km)).relative().common() == 1 * km);
static_assert(construct_from_only<abscissa<centimetre, int>>(width<cgs::centimetre, int>(1 * cgs_cm)).relative().common() == 1 * cm);
static_assert(construct_from_only<abscissa<fps::foot, double>>(width<cgs::centimetre, int>(1 * cgs_cm)).relative().common() == 1 * cm);
static_assert(construct_from_only<abscissa<metre, double>>(width<metre, int>(1 * m)).relative().common() == 1 * m);
static_assert(construct_from_only<abscissa<metre, double>>(width<millimetre, double>(1.0 * mm)).relative().common() == 1 * mm);
static_assert(construct_from_only<abscissa<metre, double>>(width<kilometre, unsigned long long>(1ULL * km)).relative().common() == 1 * km);
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(width<metre, double>(1.0 * m)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(width<millimetre, int>(1 * mm)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(height<metre, int>(1 * m)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(abscissa_kind{}, width<metre, double>(1.0 * m)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(abscissa_kind{}, width<millimetre, int>(1 * mm)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(abscissa_kind{}, height<metre, int>(1 * m)));
static_assert(construct_from_only<nth_apple<one, int>>(apples<one, int>(1)).relative().common() == 1);
static_assert(construct_from_only<nth_apple<one, double>>(apples<percent, double>(dimensionless<percent>(1))).relative().common() == 0.01);
static_assert(construct_from_only<nth_apple<percent, int>>(apples<one, int>(1)).relative().common().number() == 100);
static_assert(construct_from_only<nth_apple<percent, double>>(apples<percent, double>(dimensionless<percent>(1))).relative().common().number() == 1);
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(apples<one, double>(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(apples<percent, double>(dimensionless<percent>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(apples<one, double>(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(apples<percent, double>(dimensionless<percent>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(oranges<one, int>(1)));
// clang-format on
//////////////////////////////////////////////////
// construction from another quantity point kind
//////////////////////////////////////////////////
// clang-format off
static_assert(construct_and_convert_from<abscissa<metre, int>>(abscissa<metre, int>(1 * m)).relative().common() == 1 * m);
static_assert(construct_and_convert_from<abscissa<metre, int>>(abscissa<kilometre, unsigned long long>(1ULL * km)).relative().common() == 1 * km);
static_assert(construct_and_convert_from<abscissa<metre, double>>(abscissa<metre, unsigned long long>(1ULL * m)).relative().common() == 1 * m);
static_assert(construct_and_convert_from<abscissa<metre, double>>(abscissa<cgs::centimetre, int>(1 * cgs_cm)).relative().common() == 1 * cm);
static_assert(construct_and_convert_from<abscissa<fps::foot, double>>(abscissa<cgs::centimetre, int>(1 * cgs_cm)).relative().common() == 1 * cm);
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(abscissa<metre, double>(1.0 * m)));
static_assert(!constructible_or_convertible_from<abscissa<kilometre, int>>(abscissa<metre, int>(1 * m)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(ordinate<metre, int>(1 * m)));
static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(quantity_point_kind<time_point_kind, second, int>(1 * s)));
static_assert(construct_and_convert_from<nth_apple<one, int>>(nth_apple<one, int>(1)).relative().common() == 1);
static_assert(construct_and_convert_from<nth_apple<one, double>>(nth_apple<percent, double>(dimensionless<percent>(1))).relative().common() == 0.01);
static_assert(construct_and_convert_from<nth_apple<percent, int>>(nth_apple<one, int>(1)).relative().common().number() == 100);
static_assert(construct_and_convert_from<nth_apple<percent, double>>(nth_apple<percent, double>(dimensionless<percent>(1))).relative().common().number() == 1);
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(nth_apple<one, double>(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(nth_apple<percent, double>(dimensionless<percent>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(nth_apple<one, double>(1.0)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(nth_apple<percent, int>(dimensionless<percent, int>(1))));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(nth_orange<one, int>(1)));
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(abscissa<metre, int>(1 * m)));
// clang-format on
static_assert(!constructible_or_convertible_from<quantity_point_kind<sys_time_point_kind, second, int>>(
quantity_point_kind<time_point_kind, second, int>{}),
"no implicit conversion to/from dynamic_origin");
static_assert(!constructible_or_convertible_from<quantity_point_kind<time_point_kind, second, int>>(
quantity_point_kind<sys_time_point_kind, second, int>{}),
"no implicit conversion to/from dynamic_origin");
static_assert(!constructible_or_convertible_from<screen_si_width<metre>>(screen_si_cgs_width<metre>(1 * m)),
"base kinds are not the same (required by equivalent<Kind, Kind>)");
//////////////////////
// other conversions
//////////////////////
static_assert(!std::is_convertible_v<abscissa<metre, int>, int>);
static_assert(!std::is_convertible_v<abscissa<metre, int>, dimensionless<one, int>>);
static_assert(!std::is_convertible_v<abscissa<metre, int>, length<metre, int>>);
static_assert(!std::is_convertible_v<abscissa<metre, int>, width<metre, int>>);
static_assert(!std::is_convertible_v<abscissa<metre, int>, height<metre, int>>);
static_assert(!std::is_convertible_v<abscissa<metre, int>, quantity_point<dynamic_origin<dim_length>, metre, int>>);
////////////////////////
// assignment operator
////////////////////////
// clang-format off
static_assert((abscissa<metre, int>(2 * m) = abscissa<metre, int>(1 * m)).relative().common() == 1 * m);
static_assert((abscissa<metre, int>(2 * m) = abscissa<kilometre, int>(1 * km)).relative().common() == 1 * km);
static_assert(!std::is_assignable_v<abscissa<metre, int>, abscissa<metre, double>>);
static_assert(!std::is_assignable_v<abscissa<metre, int>, abscissa<millimetre, int>>);
// clang-format on
/////////////////////
// member operators
/////////////////////
#if !defined(UNITS_COMP_MSVC) || defined(NDEBUG)
static_assert([]() {
const width<metre, int> w(1 * m);
[[maybe_unused]] quantity_point_kind x(w);
assert(&++x == &x && x.relative().common() == 2 * m);
assert(&--x == &x && x.relative().common() == 1 * m);
assert((x++).relative().common() == 1 * m && x.relative().common() == 2 * m);
assert((x--).relative().common() == 2 * m && x.relative().common() == 1 * m);
assert(&(x += w) == &x && x.relative().common() == 2 * m);
assert(&(x -= w) == &x && x.relative().common() == 1 * m);
return true;
}());
#endif
template<typename PK, typename U, typename Qx>
concept invalid_compound_assignments_ = requires(quantity_point_kind<PK, U, int> x, Qx q) {
requires !requires { x += q; };
requires !requires { x -= q; };
};
template<typename Abscissa>
concept invalid_compound_assignments = requires(quantity_point_kind<Abscissa, metre, int> x) {
requires !requires { x += 1; };
requires !requires { x -= 1; };
requires invalid_compound_assignments_<Abscissa, metre, length<metre, int>>;
requires invalid_compound_assignments_<Abscissa, metre, height<metre, int>>;
requires invalid_compound_assignments_<Abscissa, metre, rate_of_climb<metre_per_second, int>>;
requires invalid_compound_assignments_<Abscissa, metre, quantity_point<dynamic_origin<dim_length>, metre, int>>;
requires invalid_compound_assignments_<Abscissa, metre, std::chrono::seconds>;
};
static_assert(invalid_compound_assignments<abscissa_kind>);
static_assert(invalid_compound_assignments_<time_point_kind, second, std::chrono::seconds>);
#if __cpp_lib_chrono >= 201907L
static_assert(invalid_compound_assignments_<time_point_kind, second, std::chrono::sys_seconds>);
#endif
/////////////////////////
// non-member operators
/////////////////////////
// clang-format off
static_assert(comp(abscissa<metre, int>(2 * m) + width<metre, int>(3 * m), abscissa<metre, int>(5 * m)));
static_assert(comp(abscissa<metre, int>(2 * m) + width<metre, double>(3. * m), abscissa<metre, double>(5. * m)));
static_assert(comp(abscissa<metre, double>(2. * m) + width<metre, int>(3 * m), abscissa<metre, double>(5. * m)));
static_assert(comp(abscissa<kilometre, int>(2 * km) + width<metre, double>(3e3 * m), abscissa<metre, double>(5e3 * m)));
static_assert(comp(abscissa<metre, double>(2e3 * m) + width<kilometre, int>(3 * km), abscissa<metre, double>(5e3 * m)));
static_assert(comp(width<metre, int>(2 * m) + abscissa<metre, int>(3 * m), abscissa<metre, int>(5 * m)));
static_assert(comp(width<metre, int>(2 * m) + abscissa<metre, double>(3. * m), abscissa<metre, double>(5. * m)));
static_assert(comp(width<metre, double>(2. * m) + abscissa<metre, int>(3 * m), abscissa<metre, double>(5. * m)));
static_assert(comp(width<kilometre, int>(2 * km) + abscissa<metre, double>(3e3 * m), abscissa<metre, double>(5e3 * m)));
static_assert(comp(width<metre, double>(2e3 * m) + abscissa<kilometre, int>(3 * km), abscissa<metre, double>(5e3 * m)));
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, double>);
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, length<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, abscissa<kilometre>>);
static_assert(!std::is_invocable_v<std::plus<>, abscissa<kilometre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, height<metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, quantity_point<dynamic_origin<dim_length>, metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, length<metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::plus<>, double, abscissa<metre>>);
static_assert(comp(abscissa<metre, int>(2 * m) - width<metre, int>(3 * m), abscissa<metre, int>(-1 * m)));
static_assert(comp(abscissa<metre, int>(2 * m) - width<metre, double>(3. * m), abscissa<metre, double>(-1. * m)));
static_assert(comp(abscissa<metre, double>(2. * m) - width<metre, int>(3 * m), abscissa<metre, double>(-1. * m)));
static_assert(comp(abscissa<kilometre, int>(2 * km) - width<metre, double>(3e3 * m), abscissa<metre, double>(-1e3 * m)));
static_assert(comp(abscissa<metre, double>(2e3 * m) - width<kilometre, int>(3 * km), abscissa<metre, double>(-1e3 * m)));
static_assert(same(abscissa<metre, int>(2 * m) - abscissa<metre, int>(3 * m), width<metre, int>(-1 * m)));
static_assert(same(abscissa<metre, int>(2 * m) - abscissa<metre, double>(3. * m), width<metre, double>(-1. * m)));
static_assert(same(abscissa<metre, double>(2. * m) - abscissa<metre, int>(3 * m), width<metre, double>(-1. * m)));
static_assert(comp(abscissa<kilometre, int>(2 * km) - abscissa<metre, double>(3e3 * m), width<metre, double>(-1e3 * m)));
static_assert(comp(abscissa<metre, double>(2e3 * m) - abscissa<kilometre, int>(3 * km), width<metre, double>(-1e3 * m)));
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, double>);
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, length<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, height<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, ordinate<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, ordinate<metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, height<metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, quantity_point<dynamic_origin<dim_length>, metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, length<metre>, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, double, abscissa<metre>>);
static_assert(!std::is_invocable_v<std::minus<>, screen_si_width<metre>, screen_si_cgs_width<metre>>);
// clang-format on
/////////////////////////
// comparison operators
/////////////////////////
// clang-format off
static_assert(abscissa<metre, int>(1 * m) == abscissa<metre, int>(1 * m));
static_assert(abscissa<metre, int>(1 * m) == abscissa<metre, double>(1.0 * m));
static_assert(abscissa<metre, int>(1 * m) == abscissa<millimetre, int>(1000 * mm));
static_assert(abscissa<metre, int>(1 * m) == abscissa<millimetre, double>(1e3 * mm));
static_assert(abscissa<metre, int>(2 * m) != abscissa<metre, int>(1 * m));
static_assert(abscissa<metre, int>(2 * m) != abscissa<cgs::centimetre, double>(1.0 * cgs_cm));
static_assert(std::equality_comparable_with<abscissa<metre, int>, abscissa<metre, double>>);
static_assert(std::equality_comparable_with<abscissa<nanometre, int>, abscissa<kilometre, int>>);
static_assert(std::equality_comparable_with<abscissa<cgs::centimetre, int>, abscissa<millimetre, double>>);
static_assert(std::equality_comparable_with<abscissa<metre>, abscissa<cgs::centimetre>>);
// clang-format on
template<typename Int>
concept invalid_equality = requires(quantity_point_kind<abscissa_kind, metre, Int> x, Int i) {
requires !requires { x == 1; };
requires !requires { x != 1.0; };
requires !requires { x == 1 * m; };
requires !requires { x != 1.0 * cgs_cm; };
requires !requires { x == 1 * km; };
requires !requires { x != quantity(1); };
requires !requires { x == dimensionless<percent>(1.0); };
requires !requires { x != width<metre, int>(1 * m); };
requires !requires { x == width<kilometre, double>(1.0 * km); };
requires !requires { x != height<metre, int>(1 * m); };
requires !requires { x == height<kilometre, double>(1.0 * km); };
requires !requires { x == rate_of_climb<kilometre_per_hour, double>(1.0 * (km / h)); };
requires !requires { x != quantity_point(1 * m); };
requires !requires { x == quantity_point(1.0 * mm); };
requires !requires { x != quantity_point(quantity(1)); };
requires !requires { x == quantity_point(dimensionless<percent>(1.0)); };
requires !requires { x != quantity_point_kind(cgs_width<metre, int>(1 * m)); };
requires !requires { x == ordinate<metre, int>(1 * m); };
requires !requires { screen_si_width<metre, Int>{} != screen_si_cgs_width<metre, Int>{}; };
};
static_assert(invalid_equality<int>);
// clang-format off
static_assert(abscissa<metre, int>(1 * m) < abscissa<metre, int>(2 * m));
static_assert(abscissa<metre, int>(1 * m) <= abscissa<metre, double>(2.0 * m));
static_assert(abscissa<metre, int>(1 * m) <= abscissa<kilometre, int>(1 * km));
static_assert(abscissa<metre, int>(1 * m) >= abscissa<millimetre, double>(1e3 * mm));
static_assert(abscissa<metre, int>(2 * m) >= abscissa<millimetre, int>(1 * mm));
static_assert(abscissa<metre, int>(2 * m) > abscissa<cgs::centimetre, int>(1 * cgs_cm));
static_assert(std::three_way_comparable_with<abscissa<metre, int>, abscissa<metre, double>>);
static_assert(std::three_way_comparable_with<abscissa<nanometre, int>, abscissa<kilometre, int>>);
static_assert(std::three_way_comparable_with<abscissa<cgs::centimetre, int>, abscissa<millimetre, double>>);
static_assert(std::three_way_comparable_with<abscissa<metre>, abscissa<cgs::centimetre>>);
// clang-format on
template<typename Int>
concept invalid_relational = requires(quantity_point_kind<abscissa_kind, metre, Int> x, Int i) {
requires !requires { x < 1; };
requires !requires { x <= 1.0; };
requires !requires { x >= 1 * m; };
requires !requires { x > 1.0 * cgs_cm; };
requires !requires { x <=> 1 * km; };
requires !requires { x < quantity(1); };
requires !requires { x <= dimensionless<percent>(1.0); };
requires !requires { x >= width<metre, int>(1 * m); };
requires !requires { x > width<kilometre, double>(1.0 * km); };
requires !requires { x <=> height<metre, int>(1 * m); };
requires !requires { x < height<kilometre, double>(1.0 * km); };
requires !requires { x <= rate_of_climb<kilometre_per_hour, double>(1.0 * (km / h)); };
requires !requires { x >= quantity_point(1 * m); };
requires !requires { x > quantity_point(1.0 * mm); };
requires !requires { x <=> quantity_point(quantity(1)); };
requires !requires { x < quantity_point(dimensionless<percent>(1.0)); };
requires !requires { x <= quantity_point_kind(cgs_width<metre, int>(1 * m)); };
requires !requires { x >= ordinate<metre, int>(1 * m); };
requires !requires { screen_si_width<metre, Int>{} > screen_si_cgs_width<metre, Int>{}; };
};
static_assert(invalid_relational<int>);
/////////////////////////////
// quantity_point_kind_cast
/////////////////////////////
// clang-format off
static_assert(same(quantity_point_kind_cast<abscissa<metre, int>>(abscissa<metre, int>(1 * m)), abscissa<metre, int>(1 * m)));
static_assert(same(quantity_point_kind_cast<abscissa<metre, double>>(abscissa<metre, int>(1 * m)), abscissa<metre, double>(1.0 * m)));
static_assert(same(quantity_point_kind_cast<abscissa<kilometre, int>>(abscissa<metre, int>(999 * m)), abscissa<kilometre, int>(0 * km)));
static_assert(same(quantity_point_kind_cast<abscissa<kilometre, int>>(abscissa<metre, int>(1000 * m)), abscissa<kilometre, int>(1 * km)));
static_assert(same(quantity_point_kind_cast<abscissa<kilometre, double>>(abscissa<metre, int>(999 * m)), abscissa<kilometre, double>(0.999 * km)));
static_assert(comp(quantity_point_kind_cast<width<metre, int>>(abscissa<metre, int>(1 * m)), abscissa<metre, int>(1 * m)));
static_assert(comp(quantity_point_kind_cast<width<metre, double>>(abscissa<metre, int>(1 * m)), abscissa<metre, double>(1.0 * m)));
static_assert(comp(quantity_point_kind_cast<width<kilometre, int>>(abscissa<metre, int>(999 * m)), abscissa<kilometre, int>(0 * km)));
static_assert(comp(quantity_point_kind_cast<width<kilometre, int>>(abscissa<metre, int>(1000 * m)), abscissa<kilometre, int>(1 * km)));
static_assert(comp(quantity_point_kind_cast<width<kilometre, double>>(abscissa<metre, int>(999 * m)), abscissa<kilometre, double>(0.999 * km)));
static_assert(comp(quantity_point_kind_cast<double>(abscissa<metre, int>(1 * m)), abscissa<metre, double>(1.0 * m)));
static_assert(comp(quantity_point_kind_cast<metre>(abscissa<metre, int>(1 * m)), abscissa<metre, int>(1 * m)));
static_assert(comp(quantity_point_kind_cast<kilometre>(abscissa<metre, int>(999 * m)), abscissa<kilometre, int>(0 * km)));
static_assert(comp(quantity_point_kind_cast<kilometre>(abscissa<metre, int>(1000 * m)), abscissa<kilometre, int>(1 * km)));
static_assert(same(quantity_point_kind_cast<ordinate<metre, int>>(abscissa<metre, int>(1 * m)), ordinate<metre, int>(1 * m)));
static_assert(same(quantity_point_kind_cast<ordinate<metre, double>>(abscissa<metre, int>(1 * m)), ordinate<metre, double>(1.0 * m)));
static_assert(same(quantity_point_kind_cast<ordinate<kilometre, int>>(abscissa<metre, int>(999 * m)), ordinate<kilometre, int>(0 * km)));
static_assert(same(quantity_point_kind_cast<ordinate<kilometre, int>>(abscissa<metre, int>(1000 * m)), ordinate<kilometre, int>(1 * km)));
static_assert(same(quantity_point_kind_cast<ordinate<kilometre, double>>(abscissa<metre, int>(999 * m)), ordinate<kilometre, double>(0.999 * km)));
static_assert(comp(quantity_point_kind_cast<height<metre, int>>(abscissa<metre, int>(1 * m)), ordinate<metre, int>(1 * m)));
static_assert(comp(quantity_point_kind_cast<height<metre, double>>(abscissa<metre, int>(1 * m)), ordinate<metre, double>(1.0 * m)));
static_assert(comp(quantity_point_kind_cast<height<kilometre, int>>(abscissa<metre, int>(999 * m)), ordinate<kilometre, int>(0 * km)));
static_assert(comp(quantity_point_kind_cast<height<kilometre, int>>(abscissa<metre, int>(1000 * m)), ordinate<kilometre, int>(1 * km)));
static_assert(comp(quantity_point_kind_cast<height<kilometre, double>>(abscissa<metre, int>(999 * m)), ordinate<kilometre, double>(0.999 * km)));
static_assert(comp(quantity_point_kind_cast<height_kind>(abscissa<metre, int>(1 * m)), ordinate<metre, int>(1 * m)));
static_assert(same(quantity_point_kind_cast<ordinate_kind, metre>(abscissa<metre, int>(1 * m)), ordinate<metre, int>(1 * m)));
static_assert(same(quantity_point_kind_cast<ordinate_kind, kilometre>(abscissa<metre, int>(999 * m)), ordinate<kilometre, int>(0 * km)));
static_assert(same(quantity_point_kind_cast<ordinate_kind, kilometre>(abscissa<metre, int>(1000 * m)), ordinate<kilometre, int>(1 * km)));
static_assert(same(quantity_point_kind_cast<cgs_width<cgs::centimetre, int>>(abscissa<centimetre, int>(1 * cm)), quantity_point_kind(cgs_width<cgs::centimetre, int>(1 * cgs_cm))));
static_assert(same(quantity_point_kind_cast<cgs_width_kind>(abscissa<centimetre, int>(1 * cm)), quantity_point_kind(cgs_width<cgs::centimetre, int>(1 * cgs_cm))));
static_assert(comp(quantity_point_kind_cast<altitude_kind>(abscissa<centimetre, int>(1 * cm)), altitude<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_point_kind_cast<altitude_kind, cgs::centimetre>(abscissa<centimetre, int>(1 * cm)), altitude<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_point_kind_cast<cgs_width_kind>(abscissa<metre, int>(1 * m)), quantity_point_kind(cgs_width<metre, int>(1 * m))));
static_assert(comp(quantity_point_kind_cast<altitude_kind>(abscissa<metre, int>(1 * m)), altitude<metre, int>(1 * m)));
static_assert(same(quantity_point_kind_cast<altitude_kind, metre>(abscissa<metre, int>(1 * m)), altitude<metre, int>(1 * m)));
static_assert(comp(quantity_point_kind_cast<cgs::dim_length>(abscissa<centimetre, int>(1 * cm)), abscissa<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(comp(quantity_point_kind_cast<length<kilometre, int>>(abscissa<metre, int>(1 * m)), abscissa<kilometre, int>(0 * km)));
static_assert(comp(quantity_point_kind_cast<length<centimetre, int>>(abscissa<metre, int>(1 * m)), abscissa<centimetre, int>(100 * cm)));
static_assert(comp(quantity_point_kind_cast<length<centimetre, int>>(abscissa<metre, double>(0.01 * m)), abscissa<centimetre, int>(1 * cm)));
static_assert(comp(quantity_point_kind_cast<length<centimetre, int>>(abscissa<cgs::centimetre, int>(1 * cgs_cm)), abscissa<cgs::centimetre, int>(1 * cgs_cm)));
static_assert(same(quantity_point_kind_cast<screen_si_cgs_width<metre, int>>(screen_si_width<metre, int>(1 * m)), screen_si_cgs_width<metre, int>(1 * m)));
// clang-format on
template<typename Int>
concept invalid_cast = requires(Int i) {
requires !requires { quantity_point_kind_cast<apples<one, Int>>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<rate_of_climb<metre_per_second, Int>>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<apple>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<rate_of_climb_kind>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<apple, one>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<width_kind, metre>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<width_kind, kilometre>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<height_kind, metre>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<height_kind, kilometre>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<cgs_width_kind, cgs::centimetre>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<rate_of_climb_kind, metre_per_second>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<dimensionless<one>>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<square_metre>(abscissa<metre, Int>(i * m)); };
requires !requires { quantity_point_kind_cast<second>(abscissa<metre, Int>(i * m)); };
requires !requires {
quantity_point_kind_cast<quantity_point<dynamic_origin<dim_length>, metre, Int>>(abscissa<metre, Int>(i * m));
};
requires !requires {
quantity_point_kind_cast<quantity_point<dynamic_origin<dim_one>, one, Int>>(abscissa<metre, Int>(i * m));
};
requires !requires {
quantity_point_kind_cast<quantity_point<dynamic_origin<dim_length>, metre, Int>>(
screen_si_width<metre, Int>(i * m));
};
};
static_assert(invalid_cast<int>);
/////////////////////////
// extensible interface
/////////////////////////
namespace mylib {
struct width_kind : kind<width_kind, units::isq::si::dim_length> {};
struct height_kind : kind<height_kind, units::isq::si::dim_length> {};
struct abscissa_kind : point_kind<abscissa_kind, width_kind> {};
struct ordinate_kind : point_kind<ordinate_kind, height_kind> {};
struct point {};
template<units::QuantityPointKindOf<abscissa_kind> Abscissa, units::QuantityPointKindOf<ordinate_kind> Ordinate>
point operator+(Abscissa, Ordinate);
} // namespace mylib
namespace yourapp {
static_assert(
is_same_v<mylib::point, decltype(quantity_point_kind(quantity_kind<mylib::width_kind, metre, int>(1 * m)) +
quantity_point_kind(quantity_kind<mylib::height_kind, metre, int>(1 * m)))>);
} // namespace yourapp
} // namespace