// 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/math.h" #include "units/physical/si/cgs/derived/speed.h" #include "units/physical/si/derived/area.h" #include "units/physical/si/derived/frequency.h" #include "units/physical/si/derived/speed.h" #include "units/physical/si/derived/volume.h" #include "units/physical/si/fps/derived/speed.h" #include #include #include #include #include #include namespace { using namespace units; namespace si = physical::si; using namespace si; using namespace unit_constants; constexpr auto cgs_cm = cgs::unit_constants::cm; ////////////////////////////// // quantity class invariants ////////////////////////////// static_assert(sizeof(length) == sizeof(double)); static_assert(sizeof(length) == sizeof(short)); #if UNITS_COMP_GCC != 10 || UNITS_COMP_GCC_MINOR > 2 template typename Q> concept invalid_types = requires { requires !requires { typename Q; }; // unit of a different dimension requires !requires { typename Q>; }; // quantity used as Rep requires !requires { typename Q; }; // reordered arguments requires !requires { typename Q; }; // reordered arguments }; static_assert(invalid_types); #endif static_assert(std::is_trivially_default_constructible_v>); static_assert(std::is_trivially_copy_constructible_v>); static_assert(std::is_trivially_move_constructible_v>); static_assert(std::is_trivially_copy_assignable_v>); static_assert(std::is_trivially_move_assignable_v>); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_nothrow_default_constructible_v>); static_assert(std::is_nothrow_copy_constructible_v>); static_assert(std::is_nothrow_move_constructible_v>); static_assert(std::is_nothrow_copy_assignable_v>); static_assert(std::is_nothrow_move_assignable_v>); static_assert(std::is_nothrow_destructible_v>); static_assert(std::is_trivially_copyable_v>); static_assert(std::is_standard_layout_v>); static_assert(std::default_initializable>); static_assert(std::move_constructible>); static_assert(std::copy_constructible>); static_assert(std::equality_comparable>); static_assert(std::totally_ordered>); static_assert(std::regular>); static_assert(std::three_way_comparable>); ////////////////// // member types ////////////////// static_assert(is_same_v::dimension, dim_length>); static_assert(is_same_v::dimension, fps::dim_length>); static_assert(is_same_v::unit, metre>); static_assert(is_same_v::unit, fps::mile>); static_assert(is_same_v::rep, int>); static_assert(is_same_v::rep, double>); //////////////////////////// // static member functions //////////////////////////// static_assert(length::zero().count() == 0); static_assert(length::min().count() == std::numeric_limits::lowest()); static_assert(length::max().count() == std::numeric_limits::max()); static_assert(length::zero().count() == 0.0); static_assert(length::min().count() == std::numeric_limits::lowest()); static_assert(length::max().count() == std::numeric_limits::max()); ////////////////////////////// // construction from a value ////////////////////////////// // only explicit construction from a value static_assert(std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, float>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, double>); // truncating implicit conversions double -> float allowed static_assert(!std::convertible_to>); static_assert(std::constructible_from, int>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, short>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, int>); // truncating implicit conversions int -> short allowed static_assert(!std::convertible_to>); // exception, implicit construction from a value allowed for a dimensionless quantity static_assert(std::constructible_from, double>); static_assert(std::convertible_to>); static_assert(std::constructible_from, float>); static_assert(std::convertible_to>); static_assert(std::constructible_from, double>); static_assert(std::convertible_to>); static_assert(std::constructible_from, int>); static_assert(std::convertible_to>); static_assert(std::constructible_from, short>); static_assert(std::convertible_to>); static_assert(std::constructible_from, int>); static_assert(std::convertible_to>); // but only if a dimensionless quantity has a ratio(1) static_assert(std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, float>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, double>); // truncating implicit conversions double -> float allowed static_assert(!std::convertible_to>); static_assert(std::constructible_from, int>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, short>); static_assert(!std::convertible_to>); static_assert(std::constructible_from, int>); // truncating implicit conversions int -> short allowed static_assert(!std::convertible_to>); // floating-point to integral truncating conversion not allowed static_assert(!std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, double>); static_assert(!std::convertible_to>); static_assert(length().count() == 0); // value initialization static_assert(length(1).count() == 1); static_assert(length(1.0).count() == 1.0); static_assert(length(1).count() == 1.0); static_assert(length(3.14).count() == 3.14); /////////////////////////////////////// // construction from another quantity /////////////////////////////////////// // conversion only between equivalent dimensions static_assert(std::constructible_from, length>); static_assert(std::convertible_to, length>); static_assert(std::constructible_from, cgs::length>); static_assert(std::convertible_to, length>); static_assert(std::constructible_from, cgs::length>); static_assert(std::convertible_to, fps::length>); // conversion between different dimensions not allowed static_assert(!std::constructible_from, physical::si::time>); static_assert(!std::convertible_to, length>); static_assert(!std::constructible_from, speed>); static_assert(!std::convertible_to, length>); // implicit conversion from another quantity only if non-truncating static_assert(std::constructible_from, length>); // int -> double OK static_assert(std::convertible_to, length>); // int -> double OK static_assert(!std::constructible_from, length>); // truncating double -> int not allowed static_assert(!std::convertible_to, length>); // truncating double -> int not allowed static_assert(std::constructible_from, length>); // kilometre -> metre OK static_assert(std::convertible_to, length>); // kilometre -> metre OK static_assert(!std::constructible_from, length>); // truncating metre -> kilometre not allowed static_assert(!std::convertible_to, length>); // truncating metre -> kilometre not allowed // converting to double always OK static_assert(std::constructible_from, length>); static_assert(std::convertible_to, length>); static_assert(std::constructible_from, length>); static_assert(std::convertible_to, length>); static_assert(length(123_q_m).count() == 123); static_assert(length(2_q_km).count() == 2); static_assert(length(2_q_km).count() == 2000); static_assert(length(1500_q_m).count() == 1.5); ///////// // CTAD ///////// static_assert(is_same_v(123)}), length>); static_assert(is_same_v(123)}), speed>); // static_assert(is_same_v(123)}), length>); // TODO gcc ICE static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); //////////////////////// // assignment operator //////////////////////// static_assert([]() { length l1(1), l2(2); return l2 = l1; }().count() == 1); static_assert([]() { length l1(1), l2(2); return l2 = std::move(l1); }().count() == 1); //////////////////// // unary operators //////////////////// static_assert((+123_q_m).count() == 123); static_assert((-123_q_m).count() == -123); static_assert((+(-123_q_m)).count() == -123); static_assert((-(-123_q_m)).count() == 123); static_assert([](auto v) { auto vv = v++; return std::pair(v, vv); }(123_q_m) == std::pair(124_q_m, 123_q_m)); static_assert([](auto v) { auto vv = ++v; return std::pair(v, vv); }(123_q_m) == std::pair(124_q_m, 124_q_m)); static_assert([](auto v) { auto vv = v--; return std::pair(v, vv); }(123_q_m) == std::pair(122_q_m, 123_q_m)); static_assert([](auto v) { auto vv = --v; return std::pair(v, vv); }(123_q_m) == std::pair(122_q_m, 122_q_m)); static_assert(is_same_v); //////////////////////// // compound assignment //////////////////////// // same type static_assert((1_q_m += 1_q_m).count() == 2); static_assert((2_q_m -= 1_q_m).count() == 1); static_assert((1_q_m *= 2).count() == 2); static_assert((2_q_m /= 2).count() == 1); static_assert((7_q_m %= 2).count() == 1); static_assert((1_q_m *= quantity(2)).count() == 2); static_assert((2_q_m /= quantity(2)).count() == 1); static_assert((7_q_m %= quantity(2)).count() == 1); static_assert((7_q_m %= 2_q_m).count() == 1); // different types static_assert((2.5_q_m += 3_q_m).count() == 5.5); static_assert((123_q_m += 1_q_km).count() == 1123); static_assert((5.5_q_m -= 3_q_m).count() == 2.5); static_assert((1123_q_m -= 1_q_km).count() == 123); static_assert((2.5_q_m *= 3).count() == 7.5); static_assert((7.5_q_m /= 3).count() == 2.5); static_assert((2.5_q_m *= quantity(3)).count() == 7.5); static_assert((7.5_q_m /= quantity(3)).count() == 2.5); static_assert((3500_q_m %= 1_q_km).count() == 500); static_assert((std::uint8_t(255) * m %= 256).count() == [] { std::uint8_t ui(255); return ui %= 256; }()); static_assert((std::uint8_t(255) * m %= quantity(256)).count() == [] { std::uint8_t ui(255); return ui %= 256; }()); // static_assert((std::uint8_t(255) * m %= 256 * m).count() != [] { std::uint8_t ui(255); return ui %= 256; }()); // UB static_assert((std::uint8_t(255) * m %= 257).count() == [] { std::uint8_t ui(255); return ui %= 257; }()); static_assert((std::uint8_t(255) * m %= quantity(257)).count() == [] { std::uint8_t ui(255); return ui %= 257; }()); // TODO: Fix static_assert((std::uint8_t(255) * m %= 257 * m).count() != [] { std::uint8_t ui(255); return ui %= 257; }()); #ifndef UNITS_COMP_MSVC // TODO ICE (https://developercommunity2.visualstudio.com/t/ICE-on-a-constexpr-operator-in-mp-unit/1302907) // next two lines trigger conversions warnings // (warning disabled in CMake for this file) static_assert((22_q_m *= 33.33).count() == 733); static_assert((22_q_m /= 3.33).count() == 6); static_assert((22_q_m *= quantity(33.33)).count() == 733); static_assert((22_q_m /= quantity(3.33)).count() == 6); #endif template concept invalid_compound_assignments = requires() { // truncating not allowed requires !requires(length l) { l += 2.5_q_m; }; requires !requires(length l) { l -= 2.5_q_m; }; requires !requires(length l) { l += length(2); }; requires !requires(length l) { l -= length(2); }; requires !requires(length l) { l %= length(2); }; requires !requires(length l) { l %= dimensionless(2); }; requires !requires(length l) { l %= dimensionless(2); }; // TODO: accept non-truncating argument requires !requires(length l) { l *= 1 * km / m; }; requires !requires(length l) { l /= 1 * km / m; }; requires !requires(length l) { l %= 1 * km / m; }; // only quantities can be added or subtracted requires !requires(length l) { l += 2; }; requires !requires(length l) { l -= 2; }; // compound multiply/divide by another quantity not allowed requires !requires(length l) { l *= 2_q_m; }; requires !requires(length l) { l /= 2_q_m; }; // modulo operations on a floating point representation not allowed requires !requires(length l) { l %= 2.; }; requires !requires(length l) { l %= 2; }; requires !requires(length l) { l %= 2._q_m; }; requires !requires(length l) { l %= 2_q_m; }; requires !requires(length l) { l %= 2._q_m; }; }; static_assert(invalid_compound_assignments); //////////////////// // binary operators //////////////////// template concept invalid_binary_operations = requires { // no crossdimensional addition and subtraction requires !requires { 1_q_s + length(1); }; requires !requires { 1_q_s - length(1); }; // no floating-point modulo requires !requires(length a) { a % 2_q_m; }; requires !requires(length a) { 2_q_m % a; }; requires !requires(length a) { a % 2; }; requires !requires(length a, length b) { a % b; }; requires !requires(length a, length b) { a % b; }; requires !requires(length a, length b) { b % a; }; }; static_assert(invalid_binary_operations); // same representation type static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(compare(1)), length>); static_assert(compare(1) * 1_q_m), length>); static_assert(compare(1)), length>); static_assert(compare(1)), length>); static_assert(compare>); static_assert(compare>); static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), frequency, std::int64_t>>); static_assert(is_same_v); static_assert(is_same_v); static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).count() == std::uint8_t(128) + std::uint8_t(128)); static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).count() == std::uint8_t(0) - std::uint8_t(1)); static_assert(is_same_v); // different representation types static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); // TODO should we address fundamental types implicit truncating conversions with concepts? static_assert(is_same_v>); static_assert(is_same_v>); // TODO should we address fundamental types implicit truncating conversions with concepts? static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(compare(1)), length>); static_assert(compare(1) * 1._q_m), length>); static_assert(compare>); static_assert(compare(1)), length>); static_assert(compare>); static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1._q_s), frequency, long double>>); static_assert(compare>); static_assert(compare>); static_assert(compare(1)), length>); static_assert(compare(1)), length>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(compare(1)), length>); static_assert(compare(1) * 1_q_m), length>); static_assert(compare(1)), length>); static_assert(compare>); static_assert(compare>); static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), frequency, long double>>); // different units static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); static_assert(is_same_v>); // different dimensions static_assert(compare>); static_assert(compare, std::int64_t>>); static_assert(compare, exponent>, scaled_unit, std::int64_t>>); static_assert(compare>); static_assert(compare, std::int64_t>>); static_assert(compare>); static_assert(compare>, scaled_unit, std::int64_t>>); static_assert(compare, std::int64_t>>); static_assert(compare>); static_assert(compare, std::int64_t>>); static_assert(compare, exponent>, scaled_unit, std::int64_t>>); static_assert((1_q_m + 1_q_m).count() == 2); static_assert((1_q_m + 1_q_km).count() == 1001); static_assert((1_q_km + 1_q_m).count() == 1001); static_assert((2_q_m - 1_q_m).count() == 1); static_assert((1_q_km - 1_q_m).count() == 999); static_assert((2_q_m * 2).count() == 4); static_assert((2_q_m * quantity{2}).count() == 4); static_assert((2_q_m * dimensionless(2)).count() == 4); static_assert((3 * 3_q_m).count() == 9); static_assert((quantity{3} * 3_q_m).count() == 9); static_assert((dimensionless(3) * 3_q_m).count() == 9); static_assert((4_q_m / 2).count() == 2); static_assert((4_q_m / quantity{2}).count() == 2); static_assert((4_q_m / dimensionless(2)).count() == 2); static_assert((4_q_km / 2_q_m).count() == 2); static_assert((4000_q_m / 2_q_m).count() == 2000); static_assert((1.5_q_m + 1_q_m).count() == 2.5); static_assert((1.5_q_m + 1_q_km).count() == 1001.5); static_assert((1.5_q_km + 1_q_m).count() == 1501); static_assert((2.5_q_m - 1_q_m).count() == 1.5); static_assert((1.5_q_km - 1_q_m).count() == 1499); static_assert((2.5_q_m * 2).count() == 5); static_assert((2.5_q_m * quantity{2}).count() == 5); static_assert((2.5_q_m * dimensionless(2)).count() == 5); static_assert((2.5L * 2_q_m).count() == 5); static_assert((quantity{2.5L} * 2_q_m).count() == 5); static_assert((dimensionless(2.5L) * 2_q_m).count() == 5); static_assert((5._q_m / 2).count() == 2.5); static_assert((5._q_m / quantity{2}).count() == 2.5); static_assert((5._q_m / dimensionless(2)).count() == 2.5); static_assert((5._q_km / 2_q_m).count() == 2.5); static_assert((5000._q_m / 2_q_m).count() == 2500); static_assert((1_q_m + 1.5_q_m).count() == 2.5); static_assert((1_q_m + 1.5_q_km).count() == 1501); static_assert((1_q_km + 1.5_q_m).count() == 1001.5); static_assert((2_q_m - 1.5_q_m).count() == 0.5); static_assert((1_q_km - 1.5_q_m).count() == 998.5); static_assert((2_q_m * 2.5L).count() == 5); static_assert((2_q_m * quantity{2.5L}).count() == 5); static_assert((2_q_m * dimensionless(2.5L)).count() == 5); static_assert((2 * 2.5_q_m).count() == 5); static_assert((quantity{2} * 2.5_q_m).count() == 5); static_assert((dimensionless(2) * 2.5_q_m).count() == 5); static_assert((5_q_m / 2.5L).count() == 2); static_assert((5_q_m / quantity{2.5L}).count() == 2); static_assert((5_q_m / dimensionless(2.5L)).count() == 2); static_assert((5_q_km / 2.5_q_m).count() == 2); static_assert((5000_q_m / 2.5_q_m).count() == 2000); static_assert((7_q_m % 2).count() == 1); static_assert((7_q_m % quantity{2}).count() == 1); static_assert((7_q_m % dimensionless(2)).count() == 1); static_assert((7_q_m % 2_q_m).count() == 1); static_assert((7_q_km % 2000_q_m).count() == 1000); static_assert((10_q_km2 * 10_q_km2) / 50_q_km2 == 2_q_km2); static_assert((10_q_km / 5_q_m).count() == 2); static_assert(dimensionless(10_q_km / 5_q_m).count() == 2000); #if UNITS_DOWNCAST_MODE == 0 static_assert(quantity_cast(10_q_km / 5_q_m).count() == 2000); #else static_assert(quantity_cast(10_q_km / 5_q_m).count() == 2000); #endif static_assert((10_q_s * 2_q_kHz).count() == 20); // dimensionless static_assert((quantity{3} *= quantity{2}) == 6); static_assert((quantity{6} /= quantity{2}) == 3); static_assert(quantity{1} + quantity{1} == 2); static_assert(1 + quantity{1} == 2); static_assert(quantity{1} + 1 == 2); static_assert(quantity{2} - quantity{1} == 1); static_assert(2 - quantity{1} == 1); static_assert(quantity{2} - 1 == 1); static_assert(quantity{2} * quantity{2} == 4); static_assert(2 * quantity{2} == 4); static_assert(quantity{2} * 2 == 4); static_assert(quantity{4} / quantity{2} == 2); static_assert(4 / quantity{2} == 2); static_assert(quantity{4} / 2 == 2); static_assert(quantity{4} % quantity{2} == 0); static_assert(4 % quantity{2} == 0); static_assert(quantity{4} % 2 == 0); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(quantity(1) + 2.3 == quantity(1 + 2.3)); static_assert(quantity(1) - 2.3 == quantity(1 - 2.3)); static_assert(1.2 + quantity(3) == quantity(1.2 + 3)); static_assert(1.2 - quantity(3) == quantity(1.2 - 3)); static_assert(is_same_v); static_assert(is_same_v); static_assert((quantity{std::uint8_t(128)} + quantity{std::uint8_t(128)}).count() == std::uint8_t(128) + std::uint8_t(128)); static_assert((quantity{std::uint8_t(0)} - quantity{std::uint8_t(1)}).count() == std::uint8_t(0) - std::uint8_t(1)); static_assert(is_same_v); /////////////////////// // equality operators /////////////////////// template concept no_crossdimensional_equality = requires { requires !requires { 1_q_s == length(1); }; requires !requires { 1_q_s != length(1); }; }; static_assert(no_crossdimensional_equality); // same type static_assert(length(123) == length(123)); static_assert(length(321) != length(123)); static_assert(!(length(123) == length(321))); static_assert(!(length(123) != length(123))); // different types static_assert(length(123) == length(123)); static_assert(length(321) != length(123)); static_assert(!(length(123) == length(321))); static_assert(!(length(123) != length(123))); static_assert(length(123) == length(123000)); static_assert(length(321) != length(123000)); static_assert(!(length(123) == length(321000))); static_assert(!(length(123) != length(123000))); // dimensionless static_assert(quantity{123} == 123); static_assert(quantity{321} != 123); static_assert(123 == quantity{123}); static_assert(123 != quantity{321}); /////////////////////// // ordering operators /////////////////////// template concept no_crossdimensional_ordering = requires { requires !requires { 1_q_s < length(1); }; requires !requires { 1_q_s > length(1); }; requires !requires { 1_q_s <= length(1); }; requires !requires { 1_q_s >= length(1); }; }; static_assert(no_crossdimensional_ordering); // same type static_assert(length(123) < length(321)); static_assert(length(123) <= length(123)); static_assert(length(123) <= length(321)); static_assert(length(321) > length(123)); static_assert(length(123) >= length(123)); static_assert(length(321) >= length(123)); static_assert(!(length(321) < length(123))); static_assert(!(length(123) < length(123))); static_assert(!(length(321) <= length(123))); static_assert(!(length(123) > length(321))); static_assert(!(length(123) > length(123))); static_assert(!(length(123) >= length(321))); // different types static_assert(length(123) < length(321)); static_assert(length(123) <= length(123)); static_assert(length(123) <= length(321)); static_assert(length(321) > length(123)); static_assert(length(123) >= length(123)); static_assert(length(321) >= length(123)); static_assert(!(length(321) < length(123))); static_assert(!(length(123) < length(123))); static_assert(!(length(321) <= length(123))); static_assert(!(length(123) > length(321))); static_assert(!(length(123) > length(123))); static_assert(!(length(123) >= length(321))); static_assert(length(123) < length(321000)); static_assert(length(123) <= length(123000)); static_assert(length(123) <= length(321000)); static_assert(length(321) > length(123000)); static_assert(length(123) >= length(123000)); static_assert(length(321) >= length(123000)); static_assert(!(length(321) < length(123000))); static_assert(!(length(123) < length(123000))); static_assert(!(length(321) <= length(123000))); static_assert(!(length(123) > length(321000))); static_assert(!(length(123) > length(123000))); static_assert(!(length(123) >= length(321000))); // dimensionless static_assert(quantity{123} < 321); static_assert(quantity{123} <= 123); static_assert(quantity{123} <= 321); static_assert(quantity{321} > 123); static_assert(quantity{123} >= 123); static_assert(quantity{321} >= 123); static_assert(123 < quantity{321}); static_assert(123 <= quantity{123}); static_assert(123 <= quantity{321}); static_assert(321 > quantity{123}); static_assert(123 >= quantity{123}); static_assert(321 >= quantity{123}); ////////////////// // dimensionless ////////////////// static_assert(std::equality_comparable_with, int>); static_assert(std::equality_comparable_with, double>); static_assert(std::equality_comparable_with, int>); static_assert(!std::equality_comparable_with, double>); template concept invalid_dimensionless_operations = requires { requires !requires(dimensionless d) { 1 + d; }; requires !requires(dimensionless d) { d + 1; }; }; static_assert(invalid_dimensionless_operations); static_assert(compare>); #if UNITS_DOWNCAST_MODE == 0 static_assert(quantity_cast(50._q_m / 100._q_m).count() == 50); #else static_assert(quantity_cast(50._q_m / 100._q_m).count() == 50); #endif static_assert(50._q_m / 100._q_m == dimensionless(50)); static_assert(dimensionless(dimensionless(50)).count() == 0.5); //////////////// // alias units //////////////// static_assert(compare>); static_assert(2_q_l + 2_q_ml == 2002_q_cm3); static_assert(2_q_l + 2_q_ml == 2002_q_ml); static_assert(2_q_l + 2_q_cm3 == 2002_q_ml); static_assert(2_q_dm3 + 2_q_cm3 == 2002_q_ml); ////////////////// // quantity_cast ////////////////// static_assert(quantity_cast>(2_q_km).count() == 2000); static_assert(quantity_cast>(2000_q_m).count() == 2); static_assert(quantity_cast>(1.23_q_m).count() == 1); static_assert(quantity_cast(2_q_km).count() == 2000); static_assert(quantity_cast(2000_q_m).count() == 2); static_assert(quantity_cast(1.23_q_m).count() == 1); static_assert(quantity_cast(2000.0_q_m / 3600.0_q_s).count() == 2); static_assert(quantity_cast(1 * cgs_cm) == 1 * cm); static_assert(is_same_v(2_q_dm3)), volume>); static_assert(!is_same_v(2_q_dm3)), volume>); //////////////// // downcasting //////////////// #if UNITS_DOWNCAST_MODE == 0 static_assert(is_same_v, units::exponent>, scaled_unit, std::int64_t>>); static_assert(is_same_v, std::int64_t>>); #else static_assert(is_same_v>); static_assert(is_same_v>); #endif } // namespace