refactor: got rid of gcc-9 backlog

BREAKING CHANGE: gcc-9.3 no longer supported
This commit is contained in:
Mateusz Pusz
2020-09-08 13:09:34 +02:00
parent 7ed4f19ef3
commit 4bb51586dc
27 changed files with 131 additions and 760 deletions

View File

@ -25,5 +25,4 @@ Until then, please code alike what is there already:
## Backward Compatibility
Before submission, please remember to check if the code compiles fine on all the supported compilers (especially gcc-9.3 and MSVC are tricky).
Unfortunately, we cannot add gcc-9.3 to the CI process as it is [not supported by Conan Docker images](https://github.com/conan-io/conan-docker-tools/issues/200).
Before submission, please remember to check if the code compiles fine on all the supported compilers (gcc-10 and MSVC so far).

View File

@ -66,8 +66,8 @@ class UnitsConan(ConanFile):
compiler = self.settings.compiler
version = Version(self.settings.compiler.version)
if compiler == "gcc":
if version < "9.3":
raise ConanInvalidConfiguration("mp-units requires at least g++-9.3")
if version < "10.0":
raise ConanInvalidConfiguration("mp-units requires at least g++-10")
elif compiler == "Visual Studio":
if version < "16":
raise ConanInvalidConfiguration("mp-units requires at least MSVC 16")
@ -88,11 +88,6 @@ class UnitsConan(ConanFile):
def configure(self):
self._validate_compiler_settings()
def requirements(self):
if ((self.settings.compiler == "gcc" and Version(self.settings.compiler.version) < "10") or
self.settings.compiler == "clang"):
self.requires("range-v3/0.11.0")
def build_requirements(self):
if self._run_tests:
self.build_requires("catch2/2.13.0")
@ -123,10 +118,6 @@ class UnitsConan(ConanFile):
"-Wno-literal-suffix",
"-Wno-non-template-friend",
]
if version < "10":
self.cpp_info.cxxflags.extend([
"-fconcepts"
])
elif compiler == "Visual Studio":
self.cpp_info.cxxflags = [
"/utf-8",

View File

@ -1,7 +1,7 @@
# Release notes
- **0.6.0 WIP**
- Minimum compiler version supported changed to gcc-9.3
- gcc-9 is no longer supported (at least gcc-10 is required)
- MSVC 16.7 support added
- linear_algebra updated to 0.7.0/stable
- fmt updated to 7.0.3

View File

@ -44,7 +44,7 @@ a few additional member types and functions::
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<D1, D2>)
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D1, U1, Rep1>& lhs,
[[nodiscard]] constexpr Quantity auto operator/(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
Additional functions provide the support for operations that result in a

View File

@ -16,7 +16,7 @@ with a permissive `MIT license <https://github.com/mpusz/units/blob/master/LICEN
.. note::
As this library targets C++23 and extensively uses C++20 features as of now it compiles correctly
only with gcc-9.3, MSVC 16.7, and newer.
only with gcc-10, MSVC 16.7, and newer.
.. toctree::
:maxdepth: 2

View File

@ -4,7 +4,7 @@ Usage
.. note::
This library targets C++23 and extensively uses C++20 features that is why, as of now, it compiles correctly
only with gcc-9.3, MSVC 16.7, and newer.
only with gcc-10, MSVC 16.7, and newer.
Repository Structure and Dependencies
-------------------------------------
@ -17,8 +17,6 @@ This repository contains three independent CMake-based projects:
- when this library will become part of the C++ standard it will have no external dependencies
but until then it depends on:
- `range-v3 <https://github.com/ericniebler/range-v3>`_ (only for gcc versions < 10.0) to provide
C++20 concepts library definitions.
- `{fmt} <https://github.com/fmtlib/fmt>`_ to provide text formatting of quantities.
- `ms-gsl <https://github.com/microsoft/GSL>`_ to verify runtime contracts with `Expects` macro.

View File

@ -4,7 +4,7 @@
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
// get at the units text of the quantity, without its numeric value
inline auto constexpr units_str(const units::Quantity AUTO& q)
inline auto constexpr units_str(const units::Quantity auto& q)
{
typedef std::remove_cvref_t<decltype(q)> qtype;
return units::detail::unit_text<typename qtype::dimension, typename qtype::unit>();

View File

@ -44,13 +44,13 @@ fixed_double_si_avg_speed(si::length<si::metre> d,
}
template<typename U1, typename R1, typename U2, typename R2>
constexpr Speed AUTO si_avg_speed(si::length<U1, R1> d,
constexpr Speed auto si_avg_speed(si::length<U1, R1> d,
si::time<U2, R2> t)
{
return d / t;
}
constexpr Speed AUTO avg_speed(Length AUTO d, Time AUTO t)
constexpr Speed auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
@ -68,7 +68,7 @@ void example()
// SI (int)
{
using namespace units::physical::si::literals;
constexpr Length AUTO distance = 220q_km; // constructed from a UDL
constexpr Length auto distance = 220q_km; // constructed from a UDL
constexpr si::time<si::hour, int> duration(2); // constructed from a value
std::cout << "SI units with 'int' as representation\n";
@ -82,7 +82,7 @@ void example()
// SI (double)
{
using namespace units::physical::si::literals;
constexpr Length AUTO distance = 220.q_km; // constructed from a UDL
constexpr Length auto distance = 220.q_km; // constructed from a UDL
constexpr si::time<si::hour> duration(2); // constructed from a value
std::cout << "\nSI units with 'double' as representation\n";
@ -98,7 +98,7 @@ void example()
// Customary Units (int)
{
using namespace units::physical::international::literals;
constexpr Length AUTO distance = 140q_mi; // constructed from a UDL
constexpr Length auto distance = 140q_mi; // constructed from a UDL
constexpr si::time<si::hour, int> duration(2); // constructed from a value
std::cout << "\nUS Customary Units with 'int' as representation\n";
@ -114,7 +114,7 @@ void example()
// Customary Units (double)
{
using namespace units::physical::international::literals;
constexpr Length AUTO distance = 140.q_mi; // constructed from a UDL
constexpr Length auto distance = 140.q_mi; // constructed from a UDL
constexpr si::time<si::hour> duration(2); // constructed from a value
std::cout << "\nUS Customary Units with 'double' as representation\n";
@ -132,7 +132,7 @@ void example()
// CGS (int)
{
using namespace units::physical::cgs::literals;
constexpr Length AUTO distance = 22'000'000q_cm; // constructed from a UDL
constexpr Length auto distance = 22'000'000q_cm; // constructed from a UDL
constexpr cgs::time<si::hour, int> duration(2); // constructed from a value
std::cout << "\nCGS units with 'int' as representation\n";
@ -151,7 +151,7 @@ void example()
// CGS (double)
{
using namespace units::physical::cgs::literals;
constexpr Length AUTO distance = 22'000'000.q_cm; // constructed from a UDL
constexpr Length auto distance = 22'000'000.q_cm; // constructed from a UDL
constexpr cgs::time<si::hour> duration(2); // constructed from a value
std::cout << "\nCGS units with 'double' as representation\n";

View File

@ -41,7 +41,7 @@ int main()
constexpr auto R = 4.7q_kR;
for (auto t = 0q_ms; t <= 50q_ms; ++t) {
const Voltage AUTO Vt = V0 * units::exp(-t / (R * C));
const Voltage auto Vt = V0 * units::exp(-t / (R * C));
std::cout << "at " << t << " voltage is ";

View File

@ -34,7 +34,7 @@ int main()
auto torque = 20.0q_Nm;
auto energy = 20.0q_J;
physical::Angle AUTO angle = torque / energy;
physical::Angle auto angle = torque / energy;
std::cout << angle << '\n';
}

View File

@ -27,10 +27,7 @@
#include <units/quantity_point.h>
#include <array>
#include <iostream>
#if COMP_MSVC || COMP_GCC >= 10
#include <compare>
#endif
// horizontal/vertical vector
namespace {
@ -59,10 +56,8 @@ public:
constexpr Q magnitude() const { return magnitude_; }
template<typename QQ = Q>
[[nodiscard]] constexpr vector operator-() const
requires requires(QQ q) { -q; }
// requires requires { -magnitude(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { -magnitude(); }
{
return vector(-magnitude());
}
@ -92,15 +87,17 @@ public:
}
template<typename V>
requires (Scalar<V> || Dimensionless<V>)
[[nodiscard]] friend constexpr auto operator*(const vector& lhs, const V& value)
requires (Scalar<V> || Dimensionless<V>) && requires { lhs.magnitude() * value; }
requires requires { lhs.magnitude() * value; }
{
return vector<Q, D>(lhs.magnitude() * value);
}
template<typename V>
requires (Scalar<V> || Dimensionless<V>)
[[nodiscard]] friend constexpr auto operator*(const V& value, const vector& rhs)
requires (Scalar<V> || Dimensionless<V>) && requires { value * rhs.magnitude(); }
requires requires { value * rhs.magnitude(); }
{
return vector<Q, D>(value * rhs.magnitude());
}
@ -112,8 +109,6 @@ public:
return lhs.magnitude() / rhs.magnitude();
}
#if COMP_MSVC || COMP_GCC >= 10
template<typename Q2>
[[nodiscard]] friend constexpr auto operator<=>(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() <=> rhs.magnitude(); }
@ -128,56 +123,8 @@ public:
return lhs.magnitude() == rhs.magnitude();
}
#else
template<typename Q2>
[[nodiscard]] friend constexpr auto operator==(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() == rhs.magnitude(); }
{
return lhs.magnitude() == rhs.magnitude();
}
template<typename Q2>
[[nodiscard]] friend constexpr auto operator!=(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() != rhs.magnitude(); }
{
return !(lhs == rhs);
}
template<typename Q2>
[[nodiscard]] friend constexpr auto operator<(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() < rhs.magnitude(); }
{
return lhs.magnitude() < rhs.magnitude();
}
template<typename Q2>
[[nodiscard]] friend constexpr auto operator>(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() > rhs.magnitude(); }
{
return rhs < lhs;
}
template<typename Q2>
[[nodiscard]] friend constexpr auto operator<=(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() <= rhs.magnitude(); }
{
return !(rhs < lhs);
}
template<typename Q2>
[[nodiscard]] friend constexpr auto operator>=(const vector& lhs, const vector<Q2, D>& rhs)
requires requires { lhs.magnitude() >= rhs.magnitude(); }
{
return !(lhs < rhs);
}
#endif
// template<class CharT, class Traits>
// requires Quantity<Q> // TODO gated by gcc-9 (fixed in gcc-10)
template<class CharT, class Traits, typename QQ = Q>
requires Quantity<QQ>
template<class CharT, class Traits>
requires Quantity<Q>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const vector& v)
{
return os << v.magnitude();
@ -278,7 +225,7 @@ auto get_gliders()
return gliders;
}
constexpr Dimensionless AUTO glide_ratio(const glider::polar_point& polar)
constexpr Dimensionless auto glide_ratio(const glider::polar_point& polar)
{
return polar.v / -polar.climb;
}

View File

@ -27,7 +27,7 @@
using namespace units::physical;
constexpr Speed AUTO avg_speed(Length AUTO d, Time AUTO t)
constexpr Speed auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
@ -35,10 +35,10 @@ constexpr Speed AUTO avg_speed(Length AUTO d, Time AUTO t)
int main()
{
using namespace units::physical::si::literals;
Speed AUTO v1 = avg_speed(220q_km, 2q_h);
Speed AUTO v2 = avg_speed(si::length<international::mile>(140), si::time<si::hour>(2));
Speed AUTO v3 = quantity_cast<si::metre_per_second>(v2);
Speed AUTO v4 = quantity_cast<int>(v3);
Speed auto v1 = avg_speed(220q_km, 2q_h);
Speed auto v2 = avg_speed(si::length<international::mile>(140), si::time<si::hour>(2));
Speed auto v3 = quantity_cast<si::metre_per_second>(v2);
Speed auto v4 = quantity_cast<int>(v3);
std::cout << v1 << '\n'; // 110 km/h
std::cout << fmt::format("{}", v2) << '\n'; // 70 mi/h

View File

@ -22,11 +22,8 @@
#include <units/physical/si/acceleration.h>
#include <cmath>
#include <iostream>
#if COMP_MSVC || COMP_GCC >= 10
#include <compare>
#endif
#include <iostream>
namespace {
@ -105,41 +102,8 @@ public:
return measurement(val, val * rhs.relative_uncertainty());
}
#if COMP_MSVC || COMP_GCC >= 10
[[nodiscard]] constexpr auto operator<=>(const measurement&) const = default;
#else
[[nodiscard]] friend constexpr bool operator==(const measurement& lhs, const measurement& rhs)
{
return lhs.value() == rhs.value() && lhs.uncertainty() == rhs.uncertainty();
}
[[nodiscard]] friend constexpr bool operator!=(const measurement& lhs, const measurement& rhs)
{
return !(lhs == rhs);
}
[[nodiscard]] friend constexpr bool operator<(const measurement& lhs, const measurement& rhs)
{
return lhs.value() == rhs.value() ? lhs.uncertainty() < rhs.uncertainty() : lhs.value() < rhs.value();
}
[[nodiscard]] friend constexpr bool operator>(const measurement& lhs, const measurement& rhs) { return rhs < lhs; }
[[nodiscard]] friend constexpr bool operator<=(const measurement& lhs, const measurement& rhs)
{
return !(rhs < lhs);
}
[[nodiscard]] friend constexpr bool operator>=(const measurement& lhs, const measurement& rhs)
{
return !(lhs < rhs);
}
#endif
friend std::ostream& operator<<(std::ostream& os, const measurement& v)
{
return os << v.value() << " ± " << v.uncertainty();
@ -166,7 +130,7 @@ void example()
const auto a = si::acceleration<si::metre_per_second_sq, measurement<double>>(measurement(9.8, 0.1));
const auto t = si::time<si::second, measurement<double>>(measurement(1.2, 0.1));
const Speed AUTO v1 = a * t;
const Speed auto v1 = a * t;
std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast<si::kilometre_per_hour>(v1) << '\n';
si::length<si::metre, measurement<double>> length(measurement(123., 1.));

View File

@ -32,7 +32,7 @@ namespace {
using namespace units::physical;
Energy AUTO total_energy(Momentum AUTO p, Mass AUTO m, Speed AUTO c)
Energy auto total_energy(Momentum auto p, Mass auto m, Speed auto c)
{
return sqrt(pow<2>(p * c) + pow<2>(m * pow<2>(c)));
}
@ -42,13 +42,13 @@ void si_example()
using namespace units::physical::si;
using GeV = gigaelectronvolt;
constexpr Speed AUTO c = si2019::speed_of_light<>;
constexpr Speed auto c = si2019::speed_of_light<>;
std::cout << "\n*** SI units (c = " << c << ") ***\n";
const Momentum AUTO p = 4.q_GeV / c;
const Mass AUTO m = 3.q_GeV / pow<2>(c);
const Energy AUTO E = total_energy(p, m, c);
const Momentum auto p = 4.q_GeV / c;
const Mass auto m = 3.q_GeV / pow<2>(c);
const Energy auto E = total_energy(p, m, c);
std::cout << "[in GeV]\n"
<< "p = " << p << "\n"
@ -73,10 +73,10 @@ void natural_example()
using namespace units::physical::natural;
using GeV = gigaelectronvolt;
constexpr Speed AUTO c = speed_of_light<>;
constexpr Speed auto c = speed_of_light<>;
const momentum<GeV> p(4);
const mass<GeV> m(3);
const Energy AUTO E = total_energy(p, m, c);
const Energy auto E = total_energy(p, m, c);
std::cout << "\n*** Natural units (c = " << c << ") ***\n"
<< "p = " << p << "\n"

View File

@ -26,7 +26,7 @@
namespace {
template<units::physical::Length D, units::physical::Time T>
constexpr units::physical::Speed AUTO avg_speed(D d, T t)
constexpr units::physical::Speed auto avg_speed(D d, T t)
{
return d / t;
}
@ -36,13 +36,13 @@ void example()
using namespace units::physical;
using namespace units::physical::si::literals;
Length AUTO d1 = 123q_m;
Time AUTO t1 = 10q_s;
Speed AUTO v1 = avg_speed(d1, t1);
Length auto d1 = 123q_m;
Time auto t1 = 10q_s;
Speed auto v1 = avg_speed(d1, t1);
auto temp1 = v1 * 50q_m; // produces intermediate unknown dimension with 'unknown_coherent_unit' as its 'coherent_unit'
Speed AUTO v2 = temp1 / 100q_m; // back to known dimensions again
Length AUTO d2 = v2 * 60q_s;
Speed auto v2 = temp1 / 100q_m; // back to known dimensions again
Length auto d2 = v2 * 60q_s;
std::cout << "d1 = " << d1 << '\n';
std::cout << "t1 = " << t1 << '\n';

View File

@ -74,17 +74,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-Wno-literal-suffix
-Wno-non-template-friend
)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
target_compile_options(mp-units
INTERFACE
-fconcepts
)
target_link_libraries(mp-units
INTERFACE
$<IF:$<TARGET_EXISTS:CONAN_PKG::range-v3>,CONAN_PKG::range-v3,range-v3::range-v3>
)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(mp-units
INTERFACE

View File

@ -76,16 +76,8 @@ using common_quantity_point = decltype(
} // namespace units
#if COMP_MSVC || COMP_GCC >= 10
namespace std {
#else
namespace concepts {
#endif
template<units::Quantity Q1, units::Quantity Q2>
requires units::equivalent_dim<typename Q1::dimension, typename Q2::dimension>
struct common_type<Q1, Q2> {

View File

@ -26,10 +26,7 @@
#include <algorithm>
#include <cstdlib>
#include <ostream>
#if COMP_MSVC || COMP_GCC >= 10
#include <compare>
#endif
namespace units {
@ -76,8 +73,6 @@ struct basic_fixed_string {
return basic_fixed_string<CharT, N + N2>(txt);
}
#if COMP_MSVC || COMP_GCC >= 10
[[nodiscard]] constexpr bool operator==(const basic_fixed_string& other) const
{
return std::ranges::equal(*this, other);
@ -92,74 +87,6 @@ struct basic_fixed_string {
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
#else
[[nodiscard]] constexpr friend bool operator==(const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept
{
for (size_t i = 0; i != lhs.size(); ++i)
if (lhs.data_[i] != rhs.data_[i]) return false;
return true;
}
[[nodiscard]] constexpr friend bool operator!=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept
{
return !(lhs == rhs);
}
template<typename CharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator==(const basic_fixed_string&,
const basic_fixed_string<CharT2, N2>&) noexcept
{
return false;
}
template<typename CharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator!=(const basic_fixed_string&,
const basic_fixed_string<CharT2, N2>&) noexcept
{
return true;
}
template<typename CharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator<(const basic_fixed_string& lhs,
const basic_fixed_string<CharT2, N2>& rhs) noexcept
{
using std::begin, std::end;
auto first1 = begin(lhs.data_);
auto first2 = begin(rhs.data_);
const auto last1 = std::prev(end(lhs.data_)); // do not waste time for '\0'
const auto last2 = std::prev(end(rhs.data_));
for (; (first1 != last1) && (first2 != last2); ++first1, (void)++first2) {
if (*first1 < *first2) return true;
if (*first2 < *first1) return false;
}
return first1 == last1 && first2 != last2;
}
template<typename CharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator>(const basic_fixed_string& lhs,
const basic_fixed_string<CharT2, N2>& rhs) noexcept
{
return rhs < lhs;
}
template<typename CharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator<=(const basic_fixed_string& lhs,
const basic_fixed_string<CharT2, N2>& rhs) noexcept
{
return !(rhs < lhs);
}
template<typename CharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator>=(const basic_fixed_string& lhs,
const basic_fixed_string<CharT2, N2>& rhs) noexcept
{
return !(lhs < rhs);
}
#endif
template<class Traits>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
const basic_fixed_string& txt)

View File

@ -22,7 +22,7 @@
#pragma once
#include <functional>
#include <concepts>
#if __clang__
#define COMP_CLANG __clang_major__
@ -33,29 +33,6 @@
#define COMP_MSVC _MSC_VER
#endif
#if COMP_MSVC || COMP_GCC >= 10
#include <concepts>
#else
#include <concepts/concepts.hpp>
#include <range/v3/range.hpp>
#endif
#if COMP_MSVC || COMP_GCC >= 10 || COMP_CLANG >= 11
#define AUTO auto
#define SAME_AS(T) std::same_as<T>
#else
#define AUTO
#define SAME_AS(T) T
#endif
#if COMP_MSVC
#define TYPENAME typename
@ -66,53 +43,13 @@
#endif
namespace std {
#if COMP_GCC
#if COMP_GCC >= 10
namespace std {
template<class T>
concept default_constructible = constructible_from<T>;
#else
// concepts
using concepts::common_reference_with;
using concepts::common_with;
using concepts::constructible_from;
using concepts::convertible_to;
using concepts::default_constructible;
using concepts::derived_from;
using concepts::equality_comparable;
using concepts::equality_comparable_with;
// using concepts::floating_point;
using concepts::integral;
using concepts::regular;
using concepts::same_as;
using concepts::totally_ordered;
using concepts::totally_ordered_with;
namespace ranges {
using ::ranges::forward_range;
using ::ranges::range_value_t;
}
// missing in Range-v3
template<class T>
concept floating_point = std::is_floating_point_v<T>;
template<class F, class... Args>
concept invocable =
requires(F&& f, Args&&... args) {
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
};
template<class F, class... Args>
concept regular_invocable = invocable<F, Args...>;
#endif
#endif
} // namespace std
#endif

View File

@ -27,6 +27,7 @@
#include <units/bits/external/hacks.h>
#include <units/ratio.h>
#include <units/bits/external/type_traits.h>
#include <functional>
namespace units {

View File

@ -40,7 +40,7 @@ namespace units {
*/
template<std::intmax_t N, Quantity Q>
requires(N != 0)
inline Quantity AUTO pow(const Q& q) noexcept
inline Quantity auto pow(const Q& q) noexcept
requires requires { std::pow(q.count(), N); }
{
using dim = dimension_pow<typename Q::dimension, N>;
@ -70,7 +70,7 @@ inline TYPENAME Q::rep pow(const Q&) noexcept
* @return Quantity The result of computation
*/
template<Quantity Q>
inline Quantity AUTO sqrt(const Q& q) noexcept
inline Quantity auto sqrt(const Q& q) noexcept
requires requires { std::sqrt(q.count()); }
{
using dim = dimension_sqrt<typename Q::dimension>;
@ -99,7 +99,7 @@ inline quantity<D, U, Rep> exp(const quantity<D, U, Rep>& q)
* @return Quantity The absolute value of a provided quantity
*/
template<Quantity Q>
inline Quantity AUTO abs(const Q& q) noexcept
inline Quantity auto abs(const Q& q) noexcept
requires requires { std::abs(q.count()); }
{
return Q(std::abs(q.count()));
@ -115,7 +115,7 @@ inline Quantity AUTO abs(const Q& q) noexcept
*/
template<Quantity Q>
requires requires { std::numeric_limits<typename Q::rep>::epsilon(); }
constexpr Quantity AUTO epsilon() noexcept
constexpr Quantity auto epsilon() noexcept
{
return Q(std::numeric_limits<typename Q::rep>::epsilon());
}

View File

@ -29,11 +29,7 @@
#include <units/bits/to_string.h>
#include <units/dimensionless.h>
#include <units/quantity_cast.h>
#if COMP_MSVC || COMP_GCC >= 10
#include <compare>
#endif
#include <ostream>
namespace units {
@ -90,78 +86,60 @@ public:
[[nodiscard]] constexpr rep count() const noexcept { return value_; }
template<typename T = Rep>
[[nodiscard]] static constexpr quantity zero() noexcept
requires requires { quantity_values<T>::zero(); }
// requires requires { quantity_values<Rep>::zero(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { quantity_values<Rep>::zero(); }
{
return quantity(quantity_values<Rep>::zero());
}
template<typename T = Rep>
[[nodiscard]] static constexpr quantity one() noexcept
requires requires { quantity_values<T>::one(); }
// requires requires { quantity_values<Rep>::one(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { quantity_values<Rep>::one(); }
{
return quantity(quantity_values<Rep>::one());
}
template<typename T = Rep>
[[nodiscard]] static constexpr quantity min() noexcept
requires requires { quantity_values<T>::min(); }
// requires requires { quantity_values<Rep>::min(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { quantity_values<Rep>::min(); }
{
return quantity(quantity_values<Rep>::min());
}
template<typename T = Rep>
[[nodiscard]] static constexpr quantity max() noexcept
requires requires { quantity_values<T>::max(); }
// requires requires { quantity_values<Rep>::max(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { quantity_values<Rep>::max(); }
{
return quantity(quantity_values<Rep>::max());
}
[[nodiscard]] constexpr quantity operator+() const { return *this; }
template<typename T = Rep>
[[nodiscard]] constexpr quantity operator-() const
requires std::regular_invocable<std::negate<>, T>
// requires std::regular_invocable<std::negate<>, rep> // TODO gated by gcc-9 (fixed in gcc-10)
requires std::regular_invocable<std::negate<>, rep>
{
return quantity(-count());
}
template<typename T = Rep>
constexpr quantity& operator++()
requires requires(T v) { { ++v } -> SAME_AS(T&); }
// requires requires(rep v) { { ++v } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(rep v) { { ++v } -> std::same_as<rep&>; }
{
++value_;
return *this;
}
template<typename T = Rep>
[[nodiscard]] constexpr quantity operator++(int)
requires requires(T v) { { v++ } -> SAME_AS(T); }
// requires requires(rep v) { { v++ } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(rep v) { { v++ } -> std::same_as<rep>; }
{
return quantity(value_++);
}
template<typename T = Rep>
constexpr quantity& operator--()
requires requires(T v) { { --v } -> SAME_AS(T&); }
// requires requires(rep v) { { --v } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(rep v) { { --v } -> std::same_as<rep&>; }
{
--value_;
return *this;
}
template<typename T = Rep>
[[nodiscard]] constexpr quantity operator--(int)
requires requires(T v) { { v-- } -> SAME_AS(T); }
// requires requires(rep v) { { v-- } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(rep v) { { v-- } -> std::same_as<rep>; }
{
return quantity(value_--);
}
@ -198,22 +176,19 @@ public:
return *this;
}
template<Scalar Value, typename T = Rep>
constexpr quantity& operator%=(const Value& rhs)
template<Scalar Value>
requires (!treat_as_floating_point<rep>) &&
(!treat_as_floating_point<Value>) &&
requires(T v1, Value v2) { { v1 %= v2 } -> SAME_AS(T&); }
// requires(rep v1, Value v2) { { v1 %= v2 } -> SAME_AS(rep&); } // TODO gated by gcc-9 (fixed in gcc-10)
(!treat_as_floating_point<Value>)
constexpr quantity& operator%=(const Value& rhs)
requires requires(rep v1, Value v2) { { v1 %= v2 } -> std::same_as<rep&>; }
{
value_ %= rhs;
return *this;
}
template<typename T = Rep>
constexpr quantity& operator%=(const quantity& q)
requires (!treat_as_floating_point<rep>) &&
requires(T v1, T v2) { { v1 %= v2 } -> SAME_AS(T&); }
// requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as<rep&>; }
{
value_ %= q.count();
return *this;
@ -229,8 +204,8 @@ public:
}
template<typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator+(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
requires std::regular_invocable<std::plus<>, Rep, Rep2>
[[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
{
using common_rep = decltype(lhs.count() + rhs.count());
using ret = common_quantity<quantity, quantity<D, U2, Rep2>, common_rep>;
@ -244,8 +219,8 @@ public:
}
template<typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator-(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
requires std::regular_invocable<std::minus<>, Rep, Rep2>
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
{
using common_rep = decltype(lhs.count() - rhs.count());
using ret = common_quantity<quantity, quantity<D, U2, Rep2>, common_rep>;
@ -253,8 +228,8 @@ public:
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator*(const quantity& q, const Value& v)
requires std::regular_invocable<std::multiplies<>, Rep, Value>
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v)
{
using common_rep = decltype(q.count() * v);
using ret = quantity<D, U, common_rep>;
@ -262,15 +237,15 @@ public:
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator*(const Value& v, const quantity& q)
requires std::regular_invocable<std::multiplies<>, Value, Rep>
[[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q)
{
return q * v;
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator*(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::multiplies<>, Rep, Rep2>
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
{
using dim = dimension_multiply<D, D2>;
using ret_unit = downcast_unit<dim, (U::ratio / dimension_unit<D>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
@ -280,8 +255,8 @@ public:
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator/(const Value& v, const quantity& q)
requires std::regular_invocable<std::divides<>, Value, Rep>
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
{
Expects(q.count() != 0);
@ -293,8 +268,8 @@ public:
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator/(const quantity& q, const Value& v)
requires std::regular_invocable<std::divides<>, Rep, Value>
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v)
{
Expects(v != Value{0});
@ -304,8 +279,8 @@ public:
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator/(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires std::regular_invocable<std::divides<>, Rep, Rep2>
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
{
Expects(rhs.count() != 0);
@ -317,10 +292,10 @@ public:
}
template<Scalar Value>
[[nodiscard]] friend constexpr Quantity AUTO operator%(const quantity& q, const Value& v)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Value>) &&
std::regular_invocable<std::modulus<>, Rep, Value>
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& q, const Value& v)
{
using common_rep = decltype(q.count() % v);
using ret = quantity<D, U, common_rep>;
@ -328,90 +303,34 @@ public:
}
template<typename U2, typename Rep2>
[[nodiscard]] friend constexpr Quantity AUTO operator%(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Rep2>) &&
std::regular_invocable<std::modulus<>, Rep, Rep2>
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity<D, U2, Rep2>& rhs)
{
using common_rep = decltype(lhs.count() % rhs.count());
using ret = common_quantity<quantity, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() % ret(rhs).count());
}
#if COMP_MSVC || COMP_GCC >= 10
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::three_way_comparable_with<Rep, Rep2>
[[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() <=> cq(rhs).count();
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::equality_comparable_with<Rep, Rep2>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() == cq(rhs).count();
}
#else
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::equality_comparable_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() == cq(rhs).count();
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator!=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::equality_comparable_with<Rep, Rep2>
{
return !(lhs == rhs);
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator<(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() < cq(rhs).count();
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator<=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
return !(rhs < lhs);
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
return rhs < lhs;
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator>=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
std::totally_ordered_with<Rep, Rep2>
{
return !(lhs < rhs);
}
#endif
template<class CharT, class Traits>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity& q)
{

View File

@ -313,8 +313,8 @@ constexpr ratio cast_ratio(const Q1& from, const Q2& to)
* @tparam To a target quantity type to cast to
*/
template<Quantity To, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires QuantityOf<To, D>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
{
using c_ratio = std::integral_constant<ratio, detail::cast_ratio(quantity<D, U, Rep>(), To())>;
using c_rep = std::common_type_t<typename To::rep, Rep>;
@ -337,8 +337,8 @@ template<Quantity To, typename D, typename U, typename Rep>
* @tparam ToD a dimension type to use for a target quantity
*/
template<Dimension ToD, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires equivalent_dim<ToD, D>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
{
return quantity_cast<quantity<ToD, dimension_unit<ToD>, Rep>>(q);
}
@ -356,8 +356,8 @@ template<Dimension ToD, typename D, typename U, typename Rep>
* @tparam ToU a unit type to use for a target quantity
*/
template<Unit ToU, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires UnitOf<ToU, D>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
{
return quantity_cast<quantity<D, ToU, Rep>>(q);
}
@ -397,9 +397,9 @@ template<Scalar ToRep, typename D, typename U, typename Rep>
* @tparam CastSpec a target quantity point type to cast to or anything that works for quantity_cast
*/
template<typename CastSpec, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<D, U, Rep>& qp)
requires is_specialization_of<CastSpec, quantity_point> ||
requires(quantity<D, U, Rep> q) { quantity_cast<CastSpec>(q); }
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<D, U, Rep>& qp)
{
if constexpr (is_specialization_of<CastSpec, quantity_point>)
return quantity_point(quantity_cast<typename CastSpec::quantity_type>(qp.relative()));

View File

@ -24,10 +24,7 @@
#pragma once
#include <units/quantity.h>
#if COMP_MSVC || COMP_GCC >= 10
#include <compare>
#endif
namespace units {
@ -69,69 +66,53 @@ public:
[[nodiscard]] constexpr quantity_type relative() const noexcept { return q_; }
template<typename Q = quantity_type>
[[nodiscard]] static constexpr quantity_point min() noexcept
requires requires { Q::min(); }
// requires requires { quantity_type::min(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { quantity_type::min(); }
{
return quantity_point(quantity_type::min());
}
template<typename Q = quantity_type>
[[nodiscard]] static constexpr quantity_point max() noexcept
requires requires { Q::max(); }
// requires requires { quantity_type::max(); } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires { quantity_type::max(); }
{
return quantity_point(quantity_type::max());
}
template<typename Q = quantity_type>
requires requires(Q q) { ++q; }
constexpr quantity_point& operator++()
// requires requires(quantity_type q) { ++q; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(quantity_type q) { ++q; }
{
++q_;
return *this;
}
template<typename Q = quantity_type>
[[nodiscard]] constexpr quantity_point operator++(int)
requires requires(Q q) { q++; }
// requires requires(quantity_type q) { q++; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(quantity_type q) { q++; }
{
return quantity_point(q_++);
}
template<typename Q = quantity_type>
requires requires(Q q) { --q; }
constexpr quantity_point& operator--()
// requires requires(quantity_type q) { --q; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(quantity_type q) { --q; }
{
--q_;
return *this;
}
template<typename Q = quantity_type>
[[nodiscard]] constexpr quantity_point operator--(int)
requires requires(Q q) { q--; }
// requires requires(quantity_type q) { q--; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(quantity_type q) { q--; }
{
return quantity_point(q_--);
}
template<typename Q = quantity_type>
requires requires(Q q1, Q q2) { q1 += q2; }
constexpr quantity_point& operator+=(const quantity_type& q)
// requires requires(quantity_type q) { q += q; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(quantity_type q) { q += q; }
{
q_ += q;
return *this;
}
template<typename Q = quantity_type>
requires requires(Q q1, Q q2) { q1 -= q2; }
constexpr quantity_point& operator-=(const quantity_type& q)
// requires requires(quantity_type q) { q1 -= q2; } // TODO gated by gcc-9 (fixed in gcc-10)
requires requires(quantity_type q1, quantity_type q2) { q1 -= q2; }
{
q_ -= q;
return *this;
@ -139,100 +120,58 @@ public:
// Hidden Friends
// Below friend functions are to be found via argument-dependent lookup only
#if COMP_MSVC || COMP_GCC >= 10
template<QuantityPoint QP>
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs)
requires std::three_way_comparable_with<quantity_type, typename QP::quantity_type>
{
return lhs.relative() <=> rhs.relative();
}
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
{
return lhs.relative() == rhs.relative();
}
#else
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
{
return lhs.relative() == rhs.relative();
}
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator!=(const quantity_point& lhs, const QP& rhs)
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
{
return !(lhs == rhs);
}
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator<(const quantity_point& lhs, const QP& rhs)
requires std::totally_ordered_with<quantity_type, typename QP::quantity_type>
{
return lhs.relative() < rhs.relative();
}
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator<=(const quantity_point& lhs, const QP& rhs)
requires std::totally_ordered_with<quantity_type, typename QP::quantity_type>
{
return !(rhs < lhs);
}
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator>(const quantity_point& lhs, const QP& rhs)
requires std::totally_ordered_with<quantity_type, typename QP::quantity_type>
{
return rhs < lhs;
}
template<QuantityPoint QP>
[[nodiscard]] friend constexpr bool operator>=(const quantity_point& lhs, const QP& rhs)
requires std::totally_ordered_with<quantity_type, typename QP::quantity_type>
{
return !(lhs < rhs);
}
#endif
};
template<typename D, typename U, typename Rep>
quantity_point(quantity<D, U, Rep>) -> quantity_point<D, U, Rep>;
template<QuantityPoint QP, Quantity Q>
[[nodiscard]] constexpr QuantityPoint AUTO operator+(const QP& lhs, const Q& rhs)
template<Quantity Q>
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity_point& lhs, const Q& rhs)
requires requires { lhs.relative() + rhs; }
{
return quantity_point(lhs.relative() + rhs);
const auto q = lhs.relative() + rhs;
using q_type = decltype(q);
return quantity_point<typename q_type::dimension, typename q_type::unit, typename q_type::rep>(q);
}
template<Quantity Q, QuantityPoint QP>
[[nodiscard]] constexpr QuantityPoint AUTO operator+(const Q& lhs, const QP& rhs)
template<Quantity Q>
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const Q& lhs, const quantity_point& rhs)
requires requires { rhs + lhs; }
{
return rhs + lhs;
}
template<QuantityPoint QP, Quantity Q>
[[nodiscard]] constexpr QuantityPoint AUTO operator-(const QP& lhs, const Q& rhs)
template<Quantity Q>
[[nodiscard]] friend constexpr QuantityPoint auto operator-(const quantity_point& lhs, const Q& rhs)
requires requires { lhs.relative() - rhs; }
{
return quantity_point(lhs.relative() - rhs);
const auto q = lhs.relative() - rhs;
using q_type = decltype(q);
return quantity_point<typename q_type::dimension, typename q_type::unit, typename q_type::rep>(q);
}
template<QuantityPoint QP1, QuantityPoint QP2>
[[nodiscard]] constexpr Quantity AUTO operator-(const QP1& lhs, const QP2& rhs)
template<QuantityPoint QP>
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs)
requires requires { lhs.relative() - rhs.relative(); }
{
return lhs.relative() - rhs.relative();
}
template<QuantityPoint QP>
requires std::three_way_comparable_with<quantity_type, typename QP::quantity_type>
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs)
{
return lhs.relative() <=> rhs.relative();
}
template<QuantityPoint QP>
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
{
return lhs.relative() == rhs.relative();
}
};
template<typename D, typename U, typename Rep>
quantity_point(quantity<D, U, Rep>) -> quantity_point<D, U, Rep>;
namespace detail {
template<typename D, typename U, typename Rep>

View File

@ -55,24 +55,8 @@ struct ratio {
detail::normalize(num, den, exp);
}
#if COMP_MSVC || COMP_GCC >= 10
[[nodiscard]] friend constexpr bool operator==(const ratio&, const ratio&) = default;
#else
[[nodiscard]] friend constexpr bool operator==(const ratio& lhs, const ratio& rhs)
{
return lhs.num == rhs.num && lhs.den == rhs.den && lhs.exp == rhs.exp;
}
[[nodiscard]] friend constexpr bool operator!=(const ratio& lhs, const ratio& rhs)
{
return !(lhs == rhs);
}
#endif
[[nodiscard]] friend constexpr ratio operator*(const ratio& lhs, const ratio& rhs)
{
const std::intmax_t gcd1 = std::gcd(lhs.num, rhs.den);

View File

@ -25,10 +25,7 @@
#include <units/bits/external/fixed_string.h>
#include <units/bits/external/hacks.h>
#include <gsl/gsl_assert>
#if COMP_MSVC || COMP_GCC >= 10
#include <compare>
#endif
namespace units {
@ -125,8 +122,6 @@ struct basic_symbol_text {
return basic_symbol_text<StandardCharT, 1, 1>(lhs) + rhs;
}
#if COMP_MSVC || COMP_GCC >= 10
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] friend constexpr auto operator<=>(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
@ -141,217 +136,6 @@ struct basic_symbol_text {
{
return lhs.standard() == rhs.standard() && lhs.ascii() == rhs.ascii();
}
#else
// I did not update the below operators with comparing ASCII as this code is going to be deleted soon anyway...
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
{
return lhs.standard() == rhs.standard();
}
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
{
return !(lhs == rhs);
}
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text& lhs,
const basic_fixed_string<StandardCharT, N>& rhs) noexcept
{
return lhs.standard() == rhs;
}
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text& lhs,
const basic_fixed_string<StandardCharT, N>& rhs) noexcept
{
return !(lhs == rhs);
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text&,
const basic_fixed_string<StandardCharT2, N2>&) noexcept
{
return false;
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text&,
const basic_fixed_string<StandardCharT2, N2>&) noexcept
{
return true;
}
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text& lhs,
const StandardCharT (&rhs)[N + 1]) noexcept
{
return lhs.standard() == rhs;
}
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text& lhs,
const StandardCharT (&rhs)[N + 1]) noexcept
{
return !(lhs == rhs);
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text&,
const StandardCharT2 (&)[N2 + 1]) noexcept
{
return false;
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text&,
const StandardCharT2 (&)[N2 + 1]) noexcept
{
return true;
}
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text& lhs,
StandardCharT rhs) noexcept
{
return lhs.standard() == rhs;
}
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text& lhs,
StandardCharT rhs) noexcept
{
return !(lhs == rhs);
}
template<typename StandardCharT2>
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text&,
StandardCharT2) noexcept
{
return false;
}
template<typename StandardCharT2>
[[nodiscard]] constexpr friend bool operator!=(const basic_symbol_text&,
StandardCharT2) noexcept
{
return true;
}
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator<(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
{
return lhs.standard() < rhs.standard();
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator<(const basic_symbol_text& lhs,
const basic_fixed_string<StandardCharT2, N2>& rhs) noexcept
{
return lhs.standard() < rhs;
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator<(const basic_symbol_text& lhs,
const StandardCharT2 (&rhs)[N2]) noexcept
{
return lhs.standard() < basic_fixed_string(rhs);
}
template<typename StandardCharT2>
[[nodiscard]] constexpr friend bool operator<(const basic_symbol_text& lhs,
StandardCharT2 rhs) noexcept
{
return lhs.standard() < basic_fixed_string(rhs);
}
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator>(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
{
return rhs < lhs;
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator>(const basic_symbol_text& lhs,
const basic_fixed_string<StandardCharT2, N2>& rhs) noexcept
{
return rhs < lhs;
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator>(const basic_symbol_text& lhs,
const StandardCharT2 (&rhs)[N2]) noexcept
{
return rhs < lhs;
}
template<typename StandardCharT2>
[[nodiscard]] constexpr friend bool operator>(const basic_symbol_text& lhs,
StandardCharT2 rhs) noexcept
{
return rhs < lhs;
}
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator<=(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
{
return !(rhs < lhs);
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator<=(const basic_symbol_text& lhs,
const basic_fixed_string<StandardCharT2, N2>& rhs) noexcept
{
return !(rhs < lhs);
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator<=(const basic_symbol_text& lhs,
const StandardCharT2 (&rhs)[N2]) noexcept
{
return !(rhs < lhs);
}
template<typename StandardCharT2>
[[nodiscard]] constexpr friend bool operator<=(const basic_symbol_text& lhs,
StandardCharT2 rhs) noexcept
{
return !(rhs < lhs);
}
template<typename StandardCharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator>=(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, N2, M2>& rhs) noexcept
{
return !(lhs < rhs);
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator>=(const basic_symbol_text& lhs,
const basic_fixed_string<StandardCharT2, N2>& rhs) noexcept
{
return !(lhs < rhs);
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator>=(const basic_symbol_text& lhs,
const StandardCharT2 (&rhs)[N2]) noexcept
{
return !(lhs < rhs);
}
template<typename StandardCharT2>
[[nodiscard]] constexpr friend bool operator>=(const basic_symbol_text& lhs,
StandardCharT2 rhs) noexcept
{
return !(lhs < rhs);
}
#endif
};
basic_symbol_text(char) -> basic_symbol_text<char, 1, 1>;

View File

@ -25,7 +25,7 @@
using namespace units::physical;
constexpr Speed AUTO avg_speed(Length AUTO d, Time AUTO t)
constexpr Speed auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}