mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +02:00
Downcasting reworked to allow OFF and AUTO modes
This commit is contained in:
@ -47,7 +47,7 @@ enable_testing()
|
||||
add_subdirectory(test)
|
||||
|
||||
# add usage example
|
||||
add_subdirectory(example)
|
||||
# add_subdirectory(example)
|
||||
|
||||
# generate project documentation
|
||||
add_subdirectory(docs)
|
||||
|
13
conanfile.py
13
conanfile.py
@ -49,6 +49,12 @@ class UnitsConan(ConanFile):
|
||||
"fmt/7.0.3",
|
||||
"ms-gsl/3.1.0"
|
||||
)
|
||||
options = {
|
||||
"downcast": ["off", "on", "auto"]
|
||||
}
|
||||
default_options = {
|
||||
"downcast": "auto"
|
||||
}
|
||||
# scm = {
|
||||
# "type": "git",
|
||||
# "url": "auto",
|
||||
@ -63,6 +69,13 @@ class UnitsConan(ConanFile):
|
||||
|
||||
def _configure_cmake(self, folder="src"):
|
||||
cmake = CMake(self)
|
||||
if self.options.downcast_dispatch_mode == "off":
|
||||
cmake.definitions["UNITS_DOWNCAST"] = 0
|
||||
elif self.options.downcast_dispatch_mode == "on":
|
||||
cmake.definitions["UNITS_DOWNCAST"] = 1
|
||||
elif self.options.downcast_dispatch_mode == "auto":
|
||||
cmake.definitions["UNITS_DOWNCAST"] = 2
|
||||
|
||||
if self._run_tests:
|
||||
# developer's mode (unit tests, examples, documentation, restrictive compilation warnings, ...)
|
||||
cmake.configure()
|
||||
|
@ -23,12 +23,12 @@ 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, dim_invert<D2>>
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && equivalent<D1, dim_invert<D2>>
|
||||
[[nodiscard]] constexpr Scalar auto operator*(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs);
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<D1, dim_invert<D2>>)
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent<D1, dim_invert<D2>>)
|
||||
[[nodiscard]] constexpr Quantity auto operator*(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs);
|
||||
|
||||
@ -38,17 +38,17 @@ a few additional member types and functions::
|
||||
const quantity<D, U, Rep>& q);
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && equivalent_dim<D1, D2>
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && equivalent<D1, D2>
|
||||
[[nodiscard]] constexpr Scalar auto operator/(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs);
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<D1, D2>)
|
||||
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent<D1, D2>)
|
||||
[[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
|
||||
different dimension type than those of their arguments. ``equivalent_dim``
|
||||
different dimension type than those of their arguments. ``equivalent``
|
||||
constraint requires two dimensions to be either the same or have convertible
|
||||
units of base dimension (with the same reference unit).
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
namespace {
|
||||
|
||||
template<units::Quantity Target, units::Quantity Source>
|
||||
requires units::equivalent_dim<typename Source::dimension, typename Target::dimension>
|
||||
requires units::equivalent<typename Source::dimension, typename Target::dimension>
|
||||
inline constexpr std::common_type_t<typename Target::rep, typename Source::rep> conversion_factor(Target, Source)
|
||||
{
|
||||
// get quantities looking like inputs but with Q::rep that doesn't have narrowing conversion
|
||||
|
@ -27,7 +27,7 @@
|
||||
namespace {
|
||||
|
||||
template<units::Quantity Target, units::Quantity Source>
|
||||
requires units::equivalent_dim<typename Source::dimension, typename Target::dimension>
|
||||
requires units::equivalent<typename Source::dimension, typename Target::dimension>
|
||||
inline constexpr std::common_type_t<typename Target::rep, typename Source::rep> conversion_factor(Target, Source)
|
||||
{
|
||||
// get quantities looking like inputs but with Q::rep that doesn't have narrowing conversion
|
||||
|
@ -27,6 +27,9 @@ project(mp-units
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
set(DOWNCAST_MODE AUTO CACHE STRING "Select downcasting mode")
|
||||
set_property(CACHE DOWNCAST_MODE PROPERTY STRINGS AUTO ON OFF)
|
||||
|
||||
# set path to custom cmake modules
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
|
||||
|
||||
@ -63,6 +66,7 @@ target_include_directories(units
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_link_libraries(units
|
||||
INTERFACE
|
||||
@ -86,6 +90,18 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DOWNCAST_MODE STREQUAL "AUTO")
|
||||
message(STATUS "Configuring DOWNCAST_MODE=AUTOMATIC")
|
||||
target_compile_definitions(units INTERFACE DOWNCAST_MODE=2)
|
||||
elseif(DOWNCAST_MODE)
|
||||
message(STATUS "Configuring DOWNCAST_MODE=ON")
|
||||
target_compile_definitions(units INTERFACE DOWNCAST_MODE=1)
|
||||
else()
|
||||
message(STATUS "Configuring DOWNCAST_MODE=OFF")
|
||||
target_compile_definitions(units INTERFACE DOWNCAST_MODE=0)
|
||||
endif()
|
||||
|
||||
add_library(mp::units ALIAS units)
|
||||
|
||||
# installation info
|
||||
|
@ -23,15 +23,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/dimension_op.h>
|
||||
#include <units/bits/equivalent.h>
|
||||
#include <units/quantity_cast.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension D, UnitOf<D> U, Scalar Rep>
|
||||
class quantity;
|
||||
|
||||
template<Dimension D, UnitOf<D> U, Scalar Rep>
|
||||
class quantity_point;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename Q1, typename Q2, typename Rep>
|
||||
@ -55,9 +51,8 @@ struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep>
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
|
||||
static constexpr ratio r1 = D1::base_units_ratio * U1::ratio;
|
||||
static constexpr ratio r2 = D2::base_units_ratio * U2::ratio;
|
||||
using type = quantity<D1, downcast_unit<D1, common_ratio(r1, r2)>, Rep>;
|
||||
using dimension = conditional<is_instantiation_of<D1, unknown_dimension>, D2, D1>;
|
||||
using type = quantity<dimension, downcast_unit<dimension, common_ratio(U1::ratio, U2::ratio)>, Rep>;
|
||||
};
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
@ -66,7 +61,7 @@ quantity_point<D, U, Rep> common_quantity_point_impl(quantity<D, U, Rep>);
|
||||
} // namespace detail
|
||||
|
||||
template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
|
||||
requires equivalent_dim<typename Q1::dimension, typename Q2::dimension>
|
||||
requires equivalent<typename Q1::dimension, typename Q2::dimension>
|
||||
using common_quantity = detail::common_quantity_impl<Q1, Q2, Rep>::type;
|
||||
|
||||
template<QuantityPoint QP1, QuantityPoint QP2>
|
||||
@ -87,7 +82,7 @@ namespace concepts {
|
||||
#endif
|
||||
|
||||
template<units::Quantity Q1, units::Quantity Q2>
|
||||
requires units::equivalent_dim<typename Q1::dimension, typename Q2::dimension>
|
||||
requires units::equivalent<typename Q1::dimension, typename Q2::dimension>
|
||||
struct common_type<Q1, Q2> {
|
||||
using type = units::common_quantity<Q1, Q2>;
|
||||
};
|
||||
|
@ -27,40 +27,6 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
// equivalent_dim
|
||||
namespace detail {
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
using equivalent_base_dim = std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
|
||||
same_unit_reference<typename D1::base_unit, typename D2::base_unit>>;
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
struct equivalent_dim_impl : std::false_type {};
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
struct equivalent_dim_impl<D1, D2> : std::disjunction<is_same<D1, D2>, equivalent_base_dim<D1, D2>> {};
|
||||
|
||||
template<Exponent E1, Exponent E2>
|
||||
struct equivalent_exp : std::false_type {};
|
||||
|
||||
template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2>
|
||||
struct equivalent_exp<exp<Dim1, Num, Den>, exp<Dim2, Num, Den>> : equivalent_dim_impl<Dim1, Dim2> {};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct equivalent_derived_dim : std::false_type {};
|
||||
|
||||
template<typename... Es1, typename... Es2>
|
||||
requires (sizeof...(Es1) == sizeof...(Es2))
|
||||
struct equivalent_derived_dim<derived_dimension_base<Es1...>, derived_dimension_base<Es2...>> : std::conjunction<equivalent_exp<Es1, Es2>...> {};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct equivalent_dim_impl<D1, D2> : std::disjunction<is_same<D1, D2>, equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::value;
|
||||
|
||||
/**
|
||||
* @brief Unknown dimension
|
||||
*
|
||||
@ -72,9 +38,7 @@ inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::valu
|
||||
* @tparam ERest the list of exponents of ingredient dimensions
|
||||
*/
|
||||
template<Exponent E, Exponent... ERest>
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, scaled_unit<ratio(1), unknown_coherent_unit>, E, ERest...> {
|
||||
using coherent_unit = scaled_unit<ratio(1), unknown_coherent_unit>;
|
||||
};
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, unknown_coherent_unit, E, ERest...> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
98
src/include/units/bits/equivalent.h
Normal file
98
src/include/units/bits/equivalent.h
Normal file
@ -0,0 +1,98 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/concepts.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename U>
|
||||
struct equivalent_impl : std::false_type {
|
||||
};
|
||||
|
||||
// units
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
struct equivalent_impl<U1, U2> : std::disjunction<std::is_same<U1, U2>, std::is_base_of<U1, U2>, std::is_base_of<U2, U1>> {};
|
||||
|
||||
|
||||
// dimensions
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
struct equivalent_base_dim :
|
||||
std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
|
||||
same_unit_reference<typename D1::base_unit, typename D2::base_unit>> {
|
||||
};
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
struct equivalent_impl<D1, D2> : std::disjunction<std::is_same<D1, D2>, equivalent_base_dim<D1, D2>> {
|
||||
};
|
||||
|
||||
template<Exponent E1, Exponent E2>
|
||||
struct equivalent_exp : std::false_type {
|
||||
};
|
||||
|
||||
template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2>
|
||||
struct equivalent_exp<exp<Dim1, Num, Den>, exp<Dim2, Num, Den>> : equivalent_impl<Dim1, Dim2> {
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct equivalent_derived_dim : std::false_type {
|
||||
};
|
||||
|
||||
template<typename... Es1, typename... Es2>
|
||||
requires(sizeof...(Es1) == sizeof...(Es2))
|
||||
struct equivalent_derived_dim<derived_dimension_base<Es1...>, derived_dimension_base<Es2...>> :
|
||||
std::conjunction<equivalent_exp<Es1, Es2>...> {
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct equivalent_impl<D1, D2> :
|
||||
std::disjunction<std::is_same<D1, D2>, std::is_base_of<D1, D2>, std::is_base_of<D2, D1>,
|
||||
equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {
|
||||
};
|
||||
|
||||
|
||||
// additionally accounts for unknown dimensions
|
||||
template<Unit U1, Dimension D1, Unit U2, Dimension D2>
|
||||
struct equivalent_unit : std::disjunction<equivalent_impl<U1, U2>,
|
||||
std::bool_constant<U1::ratio / dimension_unit<D1>::ratio == U2::ratio / dimension_unit<D2>::ratio>> {};
|
||||
|
||||
// quantities and quantity points
|
||||
|
||||
template<typename Q1, typename Q2>
|
||||
requires (Quantity<Q1> && Quantity<Q2>) || (QuantityPoint<Q1> && QuantityPoint<Q2>)
|
||||
struct equivalent_impl<Q1, Q2> : std::disjunction<std::is_same<Q1, Q2>,
|
||||
std::conjunction<equivalent_impl<typename Q1::dimension, typename Q2::dimension>,
|
||||
equivalent_unit<typename Q1::unit, typename Q1::dimension,
|
||||
typename Q2::unit, typename Q2::dimension>>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool equivalent = detail::equivalent_impl<T, U>::value;
|
||||
|
||||
} // namespace units
|
57
src/include/units/bits/external/downcasting.h
vendored
57
src/include/units/bits/external/downcasting.h
vendored
@ -25,44 +25,75 @@
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef DOWNCAST_MODE
|
||||
#if DOWNCAST_MODE < 0 || DOWNCAST_MODE > 2
|
||||
#error "Invalid DOWNCAST_MODE value"
|
||||
#endif
|
||||
#else
|
||||
#define DOWNCAST_MODE 2
|
||||
#endif
|
||||
|
||||
namespace units {
|
||||
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using downcast_base_type = BaseType;
|
||||
friend auto downcast_guide(downcast_base);
|
||||
friend auto downcast_poison_pill(downcast_base);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept Downcastable =
|
||||
requires {
|
||||
typename T::downcast_base_type;
|
||||
} &&
|
||||
requires { typename T::downcast_base_type; } &&
|
||||
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
|
||||
|
||||
template<typename Target, Downcastable T>
|
||||
struct downcast_child : T {
|
||||
friend auto downcast_guide(typename downcast_child::downcast_base /* base */) { return Target(); }
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
concept has_downcast =
|
||||
concept has_downcast_guide =
|
||||
requires {
|
||||
downcast_guide(std::declval<downcast_base<T>>());
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept has_downcast_poison_pill =
|
||||
requires {
|
||||
downcast_poison_pill(std::declval<downcast_base<T>>());
|
||||
};
|
||||
|
||||
template<typename Target, Downcastable T>
|
||||
struct downcast_child : T {
|
||||
friend auto downcast_guide(typename T::downcast_base)
|
||||
{ return Target(); }
|
||||
};
|
||||
|
||||
template<Downcastable T>
|
||||
struct downcast_poison : T {
|
||||
friend auto downcast_poison_pill(typename T::downcast_base)
|
||||
{ return true; }
|
||||
};
|
||||
|
||||
enum class downcast_mode {
|
||||
off = 0, // no downcasting at all
|
||||
on = 1, // downcasting always forced -> compile-time errors in case of duplicated definitions
|
||||
automatic = 2 // downcasting automatically enabled if no collisions are present
|
||||
};
|
||||
|
||||
template<typename Target, Downcastable T, downcast_mode mode = static_cast<downcast_mode>(DOWNCAST_MODE)>
|
||||
struct downcast_dispatch : std::conditional_t<mode == downcast_mode::off, T,
|
||||
std::conditional_t<mode == downcast_mode::automatic && has_downcast_guide<T>,
|
||||
downcast_poison<T>, downcast_child<Target, T>>> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
constexpr auto downcast_impl()
|
||||
{
|
||||
if constexpr (has_downcast<T>)
|
||||
if constexpr(has_downcast_guide<T> && !has_downcast_poison_pill<T>)
|
||||
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
|
||||
else
|
||||
return T();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
}
|
||||
|
||||
template<Downcastable T>
|
||||
using downcast = decltype(detail::downcast_impl<T>());
|
||||
|
@ -79,7 +79,7 @@ using make_dimension = to_derived_dimension_base<typename dim_consolidate<type_l
|
||||
* @tparam ERest the list of exponents of ingredient dimensions
|
||||
*/
|
||||
template<typename Child, Unit U, Exponent E, Exponent... ERest>
|
||||
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<E, ERest...>> {
|
||||
struct derived_dimension : downcast_dispatch<Child, typename detail::make_dimension<E, ERest...>> {
|
||||
using recipe = exp_list<E, ERest...>;
|
||||
using coherent_unit = U;
|
||||
static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents());
|
||||
|
@ -70,7 +70,7 @@ struct prefix_base : downcast_base<prefix_base<PF, R>> {
|
||||
*/
|
||||
template<typename Child, PrefixFamily PF, basic_symbol_text Symbol, ratio R>
|
||||
requires (!std::same_as<PF, no_prefix>)
|
||||
struct prefix : downcast_child<Child, detail::prefix_base<PF, R>> {
|
||||
struct prefix : downcast_dispatch<Child, detail::prefix_base<PF, R>, downcast_mode::on> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
};
|
||||
|
||||
|
@ -43,10 +43,10 @@ concept safe_convertible = // exposition only
|
||||
std::convertible_to<From, To> &&
|
||||
(treat_as_floating_point<To> || (!treat_as_floating_point<From>));
|
||||
|
||||
template<typename Rep, typename UnitFrom, typename UnitTo>
|
||||
template<typename Rep, typename QuantityFrom, typename QuantityTo>
|
||||
concept safe_divisible = // exposition only
|
||||
treat_as_floating_point<Rep> ||
|
||||
is_integral(UnitFrom::ratio / UnitTo::ratio);
|
||||
is_integral(quantity_ratio(QuantityFrom{}) / quantity_ratio(QuantityTo{}));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -78,9 +78,9 @@ public:
|
||||
constexpr explicit quantity(const Value& v) : value_{static_cast<rep>(v)} {}
|
||||
|
||||
template<Quantity Q2>
|
||||
requires equivalent_dim<D, typename Q2::dimension> &&
|
||||
requires equivalent<D, typename Q2::dimension> &&
|
||||
detail::safe_convertible<typename Q2::rep, rep> &&
|
||||
detail::safe_divisible<rep, typename Q2::unit, unit>
|
||||
detail::safe_divisible<rep, Q2, quantity>
|
||||
constexpr quantity(const Q2& q) : value_{quantity_cast<quantity>(q).count()} {}
|
||||
|
||||
quantity& operator=(const quantity&) = default;
|
||||
@ -223,7 +223,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::three_way_comparable_with<Rep, Rep2>
|
||||
{
|
||||
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
|
||||
@ -232,7 +232,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::equality_comparable_with<Rep, Rep2>
|
||||
{
|
||||
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
|
||||
@ -243,7 +243,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::equality_comparable_with<Rep, Rep2>
|
||||
{
|
||||
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
|
||||
@ -252,7 +252,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::equality_comparable_with<Rep, Rep2>
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
@ -260,7 +260,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::totally_ordered_with<Rep, Rep2>
|
||||
{
|
||||
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
|
||||
@ -269,7 +269,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::totally_ordered_with<Rep, Rep2>
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
@ -277,7 +277,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::totally_ordered_with<Rep, Rep2>
|
||||
{
|
||||
return rhs < lhs;
|
||||
@ -285,7 +285,7 @@ public:
|
||||
|
||||
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> &&
|
||||
requires equivalent<D, D2> &&
|
||||
std::totally_ordered_with<Rep, Rep2>
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
@ -337,14 +337,14 @@ template<Scalar Value, typename D, typename U, typename Rep>
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
||||
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
|
||||
requires std::regular_invocable<std::multiplies<>, Rep1, Rep2> &&
|
||||
equivalent_dim<D1, dim_invert<D2>>
|
||||
equivalent<D1, dim_invert<D2>>
|
||||
{
|
||||
using common_rep = decltype(lhs.count() * rhs.count());
|
||||
const ratio r = U1::ratio * U2::ratio;
|
||||
if constexpr (treat_as_floating_point<common_rep>) {
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
|
||||
} else {
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * ipow10(r.exp)) / static_cast<common_rep>(r.den);
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::ipow10(r.exp)) / static_cast<common_rep>(r.den);
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,7 +386,7 @@ template<typename D, typename U, typename Rep, Scalar Value>
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
|
||||
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
|
||||
requires std::regular_invocable<std::divides<>, Rep1, Rep2> &&
|
||||
equivalent_dim<D1, D2>
|
||||
equivalent<D1, D2>
|
||||
{
|
||||
Expects(rhs.count() != 0);
|
||||
|
||||
|
@ -30,6 +30,14 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension D, UnitOf<D> U, Scalar Rep>
|
||||
class quantity;
|
||||
|
||||
template<Dimension D, UnitOf<D> U, Scalar Rep>
|
||||
class quantity_point;
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr std::intmax_t ipow10(std::intmax_t exp)
|
||||
{
|
||||
assert(exp >= 0);
|
||||
@ -61,10 +69,22 @@ constexpr Rep fpow10(std::intmax_t exp)
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
constexpr auto quantity_ratio(const quantity<D, U, Rep>&)
|
||||
{
|
||||
if constexpr(BaseDimension<D>) {
|
||||
return U::ratio;
|
||||
}
|
||||
else {
|
||||
return D::base_units_ratio * U::ratio / D::coherent_unit::ratio;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// QuantityOf
|
||||
template<typename T, typename Dim>
|
||||
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent_dim<typename T::dimension, Dim>;
|
||||
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent<typename T::dimension, Dim>;
|
||||
|
||||
// quantity_cast
|
||||
namespace detail {
|
||||
@ -290,17 +310,10 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
|
||||
}
|
||||
};
|
||||
|
||||
template<Dimension FromD, Unit FromU, Dimension ToD, Unit ToU>
|
||||
constexpr ratio cast_ratio()
|
||||
template<typename Q1, typename Q2>
|
||||
constexpr ratio cast_ratio(const Q1& from, const Q2& to)
|
||||
{
|
||||
if constexpr(BaseDimension<FromD> || same_unit_reference<FromU, ToU>::value) {
|
||||
return FromU::ratio / ToU::ratio;
|
||||
}
|
||||
else {
|
||||
const ratio from_ratio = FromD::base_units_ratio * FromU::ratio;
|
||||
const ratio to_ratio = ToD::base_units_ratio * ToU::ratio;
|
||||
return from_ratio / to_ratio;
|
||||
}
|
||||
return quantity_ratio(from) / quantity_ratio(to);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@ -321,7 +334,7 @@ template<Quantity To, typename D, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
||||
requires QuantityOf<To, D>
|
||||
{
|
||||
using c_ratio = std::integral_constant<ratio, detail::cast_ratio<D, U, typename To::dimension, typename To::unit>()>;
|
||||
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>;
|
||||
using ret_unit = downcast_unit<typename To::dimension, To::unit::ratio>;
|
||||
using ret = quantity<typename To::dimension, ret_unit, typename To::rep>;
|
||||
@ -343,7 +356,7 @@ template<Quantity To, typename D, typename U, typename Rep>
|
||||
*/
|
||||
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>
|
||||
requires equivalent<ToD, D>
|
||||
{
|
||||
return quantity_cast<quantity<ToD, dimension_unit<ToD>, Rep>>(q);
|
||||
}
|
||||
|
@ -74,18 +74,11 @@ struct same_unit_reference : is_same<typename U1::reference, typename U2::refere
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
*/
|
||||
template<typename Child>
|
||||
struct unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
|
||||
struct unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
|
||||
static constexpr bool is_named = false;
|
||||
using prefix_family = no_prefix;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Unknown unit
|
||||
*
|
||||
* Used as a coherent unit of an unknown dimension.
|
||||
*/
|
||||
struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
|
||||
|
||||
/**
|
||||
* @brief A named unit
|
||||
*
|
||||
@ -99,7 +92,7 @@ struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
|
||||
* @tparam PF no_prefix or a type of prefix family
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF>
|
||||
struct named_unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
|
||||
struct named_unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@ -121,7 +114,7 @@ struct named_unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF, ratio R, Unit U>
|
||||
requires UnitRatio<R>
|
||||
struct named_scaled_unit : downcast_child<Child, scaled_unit<R * U::ratio, typename U::reference>> {
|
||||
struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<R * U::ratio, typename U::reference>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@ -140,7 +133,7 @@ struct named_scaled_unit : downcast_child<Child, scaled_unit<R * U::ratio, typen
|
||||
*/
|
||||
template<typename Child, Prefix P, Unit U>
|
||||
requires U::is_named && std::same_as<typename P::prefix_family, typename U::prefix_family>
|
||||
struct prefixed_unit : downcast_child<Child, scaled_unit<P::ratio * U::ratio, typename U::reference>> {
|
||||
struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::ratio * U::ratio, typename U::reference>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = P::symbol + U::symbol;
|
||||
using prefix_family = no_prefix;
|
||||
@ -162,7 +155,7 @@ struct prefixed_unit : downcast_child<Child, scaled_unit<P::ratio * U::ratio, ty
|
||||
template<typename Child, DerivedDimension Dim, Unit U, Unit... URest>
|
||||
requires detail::same_scaled_units<typename Dim::recipe, U, URest...> &&
|
||||
(U::is_named && (URest::is_named && ... && true))
|
||||
struct deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
struct deduced_unit : downcast_dispatch<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
static constexpr bool is_named = false;
|
||||
static constexpr auto symbol = detail::deduced_symbol_text<Dim, U, URest...>();
|
||||
using prefix_family = no_prefix;
|
||||
@ -186,7 +179,7 @@ template<typename Child, DerivedDimension Dim, Unit U, Unit... URest>
|
||||
requires detail::same_scaled_units<typename Dim::recipe, U, URest...> &&
|
||||
(U::is_named && (URest::is_named && ... && true))
|
||||
// TODO - 'noble' is placeholder to sort of mean can pass its name on to other deduced units
|
||||
struct noble_deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
struct noble_deduced_unit : downcast_dispatch<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = detail::deduced_symbol_text<Dim, U, URest...>();
|
||||
using prefix_family = no_prefix;
|
||||
@ -210,7 +203,7 @@ struct noble_deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, U
|
||||
*/
|
||||
template<typename Child, DerivedDimension Dim, basic_symbol_text Symbol, PrefixFamily PF, Unit U, Unit... URest>
|
||||
requires detail::same_scaled_units<typename Dim::recipe, U, URest...>
|
||||
struct named_deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
struct named_deduced_unit : downcast_dispatch<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@ -259,4 +252,11 @@ struct prefixed_alias_unit : U {
|
||||
using prefix_family = no_prefix;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Unknown unit
|
||||
*
|
||||
* Used as a coherent unit of an unknown dimension.
|
||||
*/
|
||||
struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
|
||||
|
||||
} // namespace units
|
||||
|
@ -50,6 +50,8 @@ static_assert(centimetre::symbol == "cm");
|
||||
|
||||
// speed
|
||||
|
||||
static_assert((10q_cm / 5q_s).count() == 2);
|
||||
static_assert((2q_cm_per_s).count() == 2);
|
||||
static_assert(10q_cm / 5q_s == 2q_cm_per_s);
|
||||
static_assert(10q_cm / 2q_cm_per_s == 5q_s);
|
||||
static_assert(10q_cm == 2q_cm_per_s * 5q_s);
|
||||
@ -59,7 +61,11 @@ static_assert(detail::unit_text<dim_speed, centimetre_per_second>() == "cm/s");
|
||||
// area
|
||||
static_assert(centimetre::ratio / dimension_unit<dim_length>::ratio == ratio(1));
|
||||
|
||||
static_assert((1q_cm * 1q_cm).count() == 1);
|
||||
static_assert((1q_cm2).count() == 1);
|
||||
static_assert(1q_cm * 1q_cm == 1q_cm2);
|
||||
static_assert(100q_cm * 100q_cm == area<physical::si::square_metre>(1));
|
||||
static_assert(100q_cm * 100q_cm == length<physical::si::metre>(1) * length<physical::si::metre>(1));
|
||||
static_assert(100q_cm2 / 10q_cm == 10q_cm);
|
||||
|
||||
static_assert(detail::unit_text<dim_area, square_centimetre>() == basic_symbol_text("cm²", "cm^2"));
|
||||
|
@ -49,11 +49,14 @@ using amplitude_spectral_density = quantity<dim_amplitude_spectral_density, U, R
|
||||
|
||||
namespace {
|
||||
|
||||
static_assert(is_same_v<dimension_sqrt<dim_power_spectral_density>, dim_amplitude_spectral_density>);
|
||||
static_assert(is_same_v<dimension_pow<dim_amplitude_spectral_density, 2>, dim_power_spectral_density>);
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare = DOWNCAST_MODE != 0 ? is_same_v<T, U> : (is_same_v<T, U> || units::equivalent<T, U>);
|
||||
|
||||
static_assert(is_same_v<decltype(pow<2>(amplitude_spectral_density<volt_per_sqrt_hertz>(4))), decltype(power_spectral_density<sq_volt_per_hertz>(16))>);
|
||||
static_assert(is_same_v<decltype(sqrt(power_spectral_density<sq_volt_per_hertz>(16))), decltype(amplitude_spectral_density<volt_per_sqrt_hertz>(4))>);
|
||||
static_assert(compare<dimension_sqrt<dim_power_spectral_density>, dim_amplitude_spectral_density>);
|
||||
static_assert(compare<dimension_pow<dim_amplitude_spectral_density, 2>, dim_power_spectral_density>);
|
||||
|
||||
static_assert(compare<decltype(pow<2>(amplitude_spectral_density<volt_per_sqrt_hertz>(4))), decltype(power_spectral_density<sq_volt_per_hertz>(16))>);
|
||||
static_assert(compare<decltype(sqrt(power_spectral_density<sq_volt_per_hertz>(16))), decltype(amplitude_spectral_density<volt_per_sqrt_hertz>(4))>);
|
||||
|
||||
}
|
||||
|
||||
@ -63,6 +66,5 @@ struct kilogram_per_second : unit<kilogram_per_second> {};
|
||||
struct dim_mass_rate : derived_dimension<dim_mass_rate, kilogram_per_second, units::exp<dim_mass, 1>, units::exp<dim_time, -1>> {};
|
||||
struct kilogram_per_hour : deduced_unit<kilogram_per_hour, dim_mass_rate, kilogram, hour> {};
|
||||
constexpr auto a = 1q_kg / 1q_h;
|
||||
static_assert(is_same_v<decltype(a)::unit, kilogram_per_hour>);
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "units/math.h"
|
||||
#include "units/physical/international/area.h"
|
||||
#include "units/physical/si/area.h"
|
||||
#include "units/physical/si/speed.h"
|
||||
#include "units/physical/international/area.h"
|
||||
@ -27,18 +29,20 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
using namespace units::physical::si::literals;
|
||||
using namespace units::physical::international::literals;
|
||||
using namespace units;
|
||||
using namespace units::physical::si::literals;
|
||||
using namespace units::physical::international::literals;
|
||||
|
||||
static_assert(is_same_v<decltype(pow<0>(2q_m)), std::int64_t>);
|
||||
static_assert(is_same_v<decltype(pow<1>(2q_m)), decltype(2q_m)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(2q_m)), decltype(4q_m2)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(2q_km)), decltype(4q_km2)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(2q_ft)), decltype(4q_ft2)>);
|
||||
static_assert(is_same_v<decltype(sqrt(4q_m2)), decltype(2q_m)>);
|
||||
static_assert(is_same_v<decltype(sqrt(4q_km2)), decltype(2q_km)>);
|
||||
static_assert(is_same_v<decltype(sqrt(4q_ft2)), decltype(2q_ft)>);
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare = DOWNCAST_MODE != 0 ? is_same_v<T, U> : (is_same_v<T, U> || units::equivalent<T, U>);
|
||||
|
||||
static_assert(compare<decltype(pow<0>(2q_m)), std::int64_t>);
|
||||
static_assert(compare<decltype(pow<1>(2q_m)), decltype(2q_m)>);
|
||||
static_assert(compare<decltype(pow<2>(2q_m)), decltype(4q_m2)>);
|
||||
static_assert(compare<decltype(pow<2>(2q_km)), decltype(4q_km2)>);
|
||||
static_assert(compare<decltype(pow<2>(2q_ft)), decltype(4q_ft2)>);
|
||||
static_assert(compare<decltype(sqrt(4q_m2)), decltype(2q_m)>);
|
||||
static_assert(compare<decltype(sqrt(4q_km2)), decltype(2q_km)>);
|
||||
static_assert(compare<decltype(sqrt(4q_ft2)), decltype(2q_ft)>);
|
||||
|
||||
} // namespace
|
||||
|
@ -35,6 +35,9 @@ namespace {
|
||||
using namespace units;
|
||||
using namespace units::physical::si;
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare = DOWNCAST_MODE != 0 ? std::is_same_v<T, U> : (std::is_same_v<T, U> || units::equivalent<T, U>);
|
||||
|
||||
// class invariants
|
||||
|
||||
template<typename DimLength>
|
||||
@ -119,23 +122,23 @@ static_assert((quantity_point(2q_m) -= 1q_m).relative().count() == 1);
|
||||
|
||||
// non-member arithmetic operators
|
||||
|
||||
static_assert(is_same_v<decltype(quantity_point<dim_length, metre, int>() + length<metre, double>()),
|
||||
static_assert(compare<decltype(quantity_point<dim_length, metre, int>() + length<metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() + quantity_point<dim_length, metre, double>()),
|
||||
static_assert(compare<decltype(length<metre, int>() + quantity_point<dim_length, metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(is_same_v<decltype(quantity_point<dim_length, kilometre, int>() + length<metre, double>()),
|
||||
static_assert(compare<decltype(quantity_point<dim_length, kilometre, int>() + length<metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(is_same_v<decltype(length<kilometre, int>() + quantity_point<dim_length, metre, double>()),
|
||||
static_assert(compare<decltype(length<kilometre, int>() + quantity_point<dim_length, metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(is_same_v<decltype(quantity_point<dim_length, metre, double>() - length<metre, int>()),
|
||||
static_assert(compare<decltype(quantity_point<dim_length, metre, double>() - length<metre, int>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(is_same_v<decltype(quantity_point<dim_length, kilometre, double>() - length<metre, int>()),
|
||||
static_assert(compare<decltype(quantity_point<dim_length, kilometre, double>() - length<metre, int>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(quantity_point<dim_length, metre, double>() - quantity_point<dim_length, metre, int>()),
|
||||
compare<decltype(quantity_point<dim_length, metre, double>() - quantity_point<dim_length, metre, int>()),
|
||||
length<metre, double>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(quantity_point<dim_length, kilometre, double>() - quantity_point<dim_length, metre, int>()),
|
||||
compare<decltype(quantity_point<dim_length, kilometre, double>() - quantity_point<dim_length, metre, int>()),
|
||||
length<metre, double>>);
|
||||
|
||||
static_assert((1q_m + km).relative().count() == 1001);
|
||||
@ -187,13 +190,13 @@ static_assert(QuantityPoint<quantity_point<dim_length, millimetre, int>>);
|
||||
|
||||
// common_quantity_point
|
||||
|
||||
static_assert(is_same_v<
|
||||
static_assert(compare<
|
||||
common_quantity_point<quantity_point<dim_length, metre, int>, quantity_point<dim_length, kilometre, int>>,
|
||||
quantity_point<dim_length, metre, int>>);
|
||||
static_assert(is_same_v<common_quantity_point<quantity_point<dim_length, kilometre, long long>,
|
||||
static_assert(compare<common_quantity_point<quantity_point<dim_length, kilometre, long long>,
|
||||
quantity_point<dim_length, metre, int>>,
|
||||
quantity_point<dim_length, metre, long long>>);
|
||||
static_assert(is_same_v<common_quantity_point<quantity_point<dim_length, kilometre, long long>,
|
||||
static_assert(compare<common_quantity_point<quantity_point<dim_length, kilometre, long long>,
|
||||
quantity_point<dim_length, millimetre, double>>,
|
||||
quantity_point<dim_length, millimetre, double>>);
|
||||
|
||||
@ -209,7 +212,7 @@ static_assert(std::equality_comparable_with<decltype(quantity_point(1q_m)), decl
|
||||
// quantity_cast
|
||||
|
||||
static_assert(
|
||||
is_same_v<decltype(quantity_point_cast<scaled_unit<ratio(1), metre>>(quantity_point(2q_km)))::unit, metre>);
|
||||
compare<decltype(quantity_point_cast<scaled_unit<ratio(1), metre>>(quantity_point(2q_km)))::unit, metre>);
|
||||
|
||||
static_assert(quantity_point_cast<quantity_point<dim_length, metre, int>>(quantity_point(2q_km)).relative().count() ==
|
||||
2000);
|
||||
|
@ -34,6 +34,9 @@ namespace {
|
||||
using namespace units;
|
||||
using namespace units::physical::si;
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare = DOWNCAST_MODE != 0 ? std::is_same_v<T, U> : (std::is_same_v<T, U> || units::equivalent<T, U>);
|
||||
|
||||
// class invariants
|
||||
|
||||
// constexpr quantity<si::dim_length, second, int> error(0); // should not compile (unit of a different dimension)
|
||||
@ -67,7 +70,7 @@ static_assert(length<metre, double>(1000.0q_m).count() == 1000.0);
|
||||
static_assert(length<metre, double>(km).count() == 1000.0);
|
||||
static_assert(length<metre, int>(1q_km).count() == 1000);
|
||||
// static_assert(length<metre, int>(1q_s).count() == 1); // should not compile (different dimensions)
|
||||
//static_assert(length<kilometre, int>(1010q_m).count() == 1); // should not compile (truncating conversion)
|
||||
// static_assert(length<kilometre, int>(1010q_m).count() == 1); // should not compile (truncating conversion)
|
||||
|
||||
// assignment operator
|
||||
|
||||
@ -134,37 +137,34 @@ static_assert((2.5q_m *= 3.5).count() == 8.75);
|
||||
|
||||
// non-member arithmetic operators
|
||||
|
||||
static_assert(is_same_v<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
static_assert(compare<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
static_assert(compare<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
static_assert(compare<decltype(length<kilometre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
static_assert(compare<decltype(length<metre, double>() - length<metre, int>()), length<metre, double>>);
|
||||
static_assert(compare<decltype(length<kilometre, double>() - length<metre, int>()), length<metre, double>>);
|
||||
static_assert(compare<decltype(length<metre, int>() * 1.0), length<metre, double>>);
|
||||
static_assert(compare<decltype(1.0 * length<metre, int>()), length<metre, double>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(length<kilometre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
static_assert(is_same_v<decltype(length<metre, double>() - length<metre, int>()), length<metre, double>>);
|
||||
compare<decltype(speed<metre_per_second, int>() * physical::si::time<second, int>()), length<metre, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(length<kilometre, double>() - length<metre, int>()), length<metre, double>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() * 1.0), length<metre, double>>);
|
||||
static_assert(is_same_v<decltype(1.0 * length<metre, int>()), length<metre, double>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<second, int>()), length<metre, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio(36, 1, 2), metre>, int>>);
|
||||
static_assert(is_same_v<decltype(length<metre>() * physical::si::time<minute>()),
|
||||
compare<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio(36, 1, 2), metre>, int>>);
|
||||
static_assert(compare<decltype(length<metre>() * physical::si::time<minute>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6, 1, 1), unknown_coherent_unit>>>);
|
||||
static_assert(is_same_v<decltype(1 / physical::si::time<second, int>()), frequency<hertz, int>>);
|
||||
static_assert(is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio(1, 6, -1), hertz>, int>>);
|
||||
static_assert(is_same_v<decltype(1 / frequency<hertz, int>()), physical::si::time<second, int>>);
|
||||
static_assert(is_same_v<decltype(1 / length<kilometre>()),
|
||||
static_assert(compare<decltype(1 / physical::si::time<second, int>()), frequency<hertz, int>>);
|
||||
static_assert(compare<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio(1, 6, -1), hertz>, int>>);
|
||||
static_assert(compare<decltype(1 / frequency<hertz, int>()), physical::si::time<second, int>>);
|
||||
static_assert(compare<decltype(1 / length<kilometre>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>>, scaled_unit<ratio(1, 1, -3), unknown_coherent_unit>>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
|
||||
static_assert(is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
|
||||
static_assert(compare<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio(1, 6, -1), metre_per_second>>>);
|
||||
static_assert(is_same_v<decltype(physical::si::time<minute>() / length<metre>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6 ,1 , 1), unknown_coherent_unit>>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
|
||||
static_assert(is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
|
||||
compare<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio(1, 6, -1), metre_per_second>>>);
|
||||
static_assert(compare<decltype(physical::si::time<minute>() / length<metre>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6, 1, 1), unknown_coherent_unit>>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
|
||||
|
||||
static_assert((1q_m + km).count() == 1001);
|
||||
static_assert((1q_m + 1q_km).count() == 1001);
|
||||
@ -225,11 +225,10 @@ static_assert(Quantity<length<millimetre, int>>);
|
||||
|
||||
// common_quantity
|
||||
|
||||
static_assert(is_same_v<common_quantity<length<metre, int>, length<kilometre, int>>, length<metre, int>>);
|
||||
static_assert(compare<common_quantity<length<metre, int>, length<kilometre, int>>, length<metre, int>>);
|
||||
static_assert(compare<common_quantity<length<kilometre, long long>, length<metre, int>>, length<metre, long long>>);
|
||||
static_assert(
|
||||
is_same_v<common_quantity<length<kilometre, long long>, length<metre, int>>, length<metre, long long>>);
|
||||
static_assert(is_same_v<common_quantity<length<kilometre, long long>, length<millimetre, double>>,
|
||||
length<millimetre, double>>);
|
||||
compare<common_quantity<length<kilometre, long long>, length<millimetre, double>>, length<millimetre, double>>);
|
||||
|
||||
// common_type
|
||||
|
||||
@ -242,7 +241,7 @@ static_assert(std::equality_comparable_with<decltype(1q_m), decltype(1q_ft_us)>)
|
||||
|
||||
// quantity_cast
|
||||
|
||||
static_assert(is_same_v<decltype(quantity_cast<scaled_unit<ratio(1), metre>>(2q_km))::unit, metre>);
|
||||
static_assert(compare<decltype(quantity_cast<scaled_unit<ratio(1), metre>>(2q_km))::unit, metre>);
|
||||
|
||||
static_assert(quantity_cast<length<metre, int>>(2q_km).count() == 2000);
|
||||
static_assert(quantity_cast<length<kilometre, int>>(2000q_m).count() == 2);
|
||||
@ -271,6 +270,20 @@ static_assert(1q_km / 1q_s == 1000q_m_per_s);
|
||||
static_assert(2q_km_per_h * 2q_h == 4q_km);
|
||||
static_assert(2q_km / 2q_km_per_h == 1q_h);
|
||||
|
||||
static_assert(is_same_v<decltype(pow<2>(2q_m)), decltype(4q_m2)>);
|
||||
static_assert(compare<decltype(pow<2>(2q_m)), decltype(4q_m2)>);
|
||||
|
||||
// downcasting
|
||||
|
||||
#if DOWNCAST_MODE == 0
|
||||
|
||||
static_assert(std::is_same_v<decltype(10q_m / 5q_s), quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, -1>>, scaled_unit<ratio(1), unknown_coherent_unit>, std::int64_t>>);
|
||||
static_assert(std::is_same_v<decltype(1q_mm + 1q_km), length<scaled_unit<ratio(1, 1, -3), metre>, std::int64_t>>);
|
||||
|
||||
#else
|
||||
|
||||
static_assert(std::is_same_v<decltype(10q_m / 5q_s), speed<metre_per_second, std::int64_t>>);
|
||||
static_assert(std::is_same_v<decltype(1q_mm + 1q_km), length<millimetre, std::int64_t>>);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
@ -46,6 +46,13 @@ namespace {
|
||||
|
||||
using namespace units::physical;
|
||||
|
||||
static_assert(units::detail::quantity_ratio(si::length<si::metre>(1)) == units::ratio(1));
|
||||
static_assert(units::detail::quantity_ratio(cgs::length<cgs::centimetre>(1)) == units::ratio(1, 100));
|
||||
static_assert(units::detail::quantity_ratio(si::speed<si::metre_per_second>(1)) == units::ratio(1));
|
||||
static_assert(units::detail::quantity_ratio(cgs::speed<cgs::centimetre_per_second>(1)) == units::ratio(1, 100));
|
||||
static_assert(units::detail::quantity_ratio(si::force<si::newton>(1)) == units::ratio(1000)); // defined in terms of kilogram that are 1000 * gram
|
||||
static_assert(units::detail::quantity_ratio(cgs::force<cgs::dyne>(1)) == units::ratio(1, 100)); // defined in terms of gram so only centimetre ratio counts here
|
||||
|
||||
static_assert(cgs::length<cgs::centimetre>(100) == si::length<si::metre>(1));
|
||||
static_assert(cgs::mass<cgs::gram>(1'000) == si::mass<si::kilogram>(1));
|
||||
static_assert(cgs::time<cgs::second>(1) == si::time<si::second>(1));
|
||||
|
@ -52,14 +52,14 @@ static_assert(fps::time<fps::second>(1) == si::time<si::second>(1));
|
||||
static_assert(fps::speed<fps::foot_per_second>(1) == si::speed<si::metre_per_second>(0.3048));
|
||||
static_assert(fps::area<fps::square_foot>(1) == si::area<si::square_metre>(0.09290304));
|
||||
static_assert(fps::acceleration<fps::foot_per_second_sq>(1) == si::acceleration<si::metre_per_second_sq>(0.3048));
|
||||
static_assert(fps::force<fps::poundal>(1) >= si::force<si::newton>(0.138254) &&
|
||||
fps::force<fps::poundal>(1) <= si::force<si::newton>(0.138256));
|
||||
static_assert(fps::energy<fps::foot_poundal>(1) >= si::energy<si::joule>(0.042140110093804) &&
|
||||
fps::energy<fps::foot_poundal>(1) <= si::energy<si::joule>(0.042140110093806));
|
||||
static_assert(fps::power<fps::foot_poundal_per_second>(1) >= si::power<si::watt>(0.042140110093804) &&
|
||||
fps::power<fps::foot_poundal_per_second>(1) <= si::power<si::watt>(0.042140110093806));
|
||||
static_assert(fps::pressure<fps::poundal_per_foot_sq>(1) >= si::pressure<si::pascal>(1.4881639435) &&
|
||||
fps::pressure<fps::poundal_per_foot_sq>(1) <= si::pressure<si::pascal>(1.4881639437));
|
||||
static_assert(fps::force<fps::poundal>(1) > si::force<si::newton>(0.138254) &&
|
||||
fps::force<fps::poundal>(1) < si::force<si::newton>(0.138256));
|
||||
static_assert(fps::energy<fps::foot_poundal>(1) > si::energy<si::joule>(0.042140110093804) &&
|
||||
fps::energy<fps::foot_poundal>(1) < si::energy<si::joule>(0.042140110093806));
|
||||
static_assert(fps::power<fps::foot_poundal_per_second>(1) > si::power<si::watt>(0.042140110093804) &&
|
||||
fps::power<fps::foot_poundal_per_second>(1) < si::power<si::watt>(0.042140110093806));
|
||||
static_assert(fps::pressure<fps::poundal_per_foot_sq>(1) > si::pressure<si::pascal>(1.4881639435) &&
|
||||
fps::pressure<fps::poundal_per_foot_sq>(1) < si::pressure<si::pascal>(1.4881639437));
|
||||
|
||||
namespace si_literals {
|
||||
|
||||
@ -69,16 +69,17 @@ static_assert(fps::length<fps::foot>(1) == 0.3048q_m);
|
||||
static_assert(fps::mass<fps::pound>(1) == 0.45359237q_kg);
|
||||
static_assert(fps::time<fps::second>(1) == 1q_s);
|
||||
static_assert(fps::speed<fps::foot_per_second>(1) == 0.3048q_m_per_s);
|
||||
static_assert(fps::area<fps::square_foot>(1) == 0.09290304q_m2);
|
||||
static_assert(fps::area<fps::square_foot>(1) > 0.09290303q_m2 &&
|
||||
fps::area<fps::square_foot>(1) < 0.09290305q_m2);
|
||||
static_assert(fps::acceleration<fps::foot_per_second_sq>(1) == 0.3048q_m_per_s2);
|
||||
static_assert(fps::force<fps::poundal>(1) >= 0.138254q_N &&
|
||||
fps::force<fps::poundal>(1) <= 0.138256q_N);
|
||||
static_assert(fps::energy<fps::foot_poundal>(1) >= 0.042140110093804q_J &&
|
||||
fps::energy<fps::foot_poundal>(1) <= 0.042140110093806q_J);
|
||||
static_assert(fps::power<fps::foot_poundal_per_second>(1) >= 0.042140110093804q_W &&
|
||||
fps::power<fps::foot_poundal_per_second>(1) <= 0.042140110093806q_W);
|
||||
static_assert(fps::pressure<fps::poundal_per_foot_sq>(1) >= 1.4881639435q_Pa &&
|
||||
fps::pressure<fps::poundal_per_foot_sq>(1) <= 1.4881639437q_Pa);
|
||||
static_assert(fps::force<fps::poundal>(1) > 0.138254q_N &&
|
||||
fps::force<fps::poundal>(1) < 0.138256q_N);
|
||||
static_assert(fps::energy<fps::foot_poundal>(1) > 0.042140110093804q_J &&
|
||||
fps::energy<fps::foot_poundal>(1) < 0.042140110093806q_J);
|
||||
static_assert(fps::power<fps::foot_poundal_per_second>(1) > 0.042140110093804q_W &&
|
||||
fps::power<fps::foot_poundal_per_second>(1) < 0.042140110093806q_W);
|
||||
static_assert(fps::pressure<fps::poundal_per_foot_sq>(1) > 1.4881639435q_Pa &&
|
||||
fps::pressure<fps::poundal_per_foot_sq>(1) < 1.4881639437q_Pa);
|
||||
}
|
||||
|
||||
namespace fps_literals {
|
||||
@ -91,14 +92,14 @@ static_assert(1q_s == si::time<si::second>(1));
|
||||
static_assert(1q_ft_per_s == si::speed<si::metre_per_second>(0.3048));
|
||||
static_assert(1q_ft2 == si::area<si::square_metre>(0.09290304));
|
||||
static_assert(1q_ft_per_s2 == si::acceleration<si::metre_per_second_sq>(0.3048));
|
||||
static_assert(1q_pdl >= si::force<si::newton>(0.138254) &&
|
||||
1q_pdl <= si::force<si::newton>(0.138256));
|
||||
static_assert(1q_ft_pdl >= si::energy<si::joule>(0.042140110093804) &&
|
||||
1q_ft_pdl <= si::energy<si::joule>(0.042140110093806));
|
||||
static_assert(1q_ft_pdl_per_s >= si::power<si::watt>(0.042140110093804) &&
|
||||
1q_ft_pdl_per_s <= si::power<si::watt>(0.042140110093806));
|
||||
static_assert(1q_pdl_per_ft2>= si::pressure<si::pascal>(1.4881639435) &&
|
||||
1q_pdl_per_ft2 <= si::pressure<si::pascal>(1.4881639437));
|
||||
static_assert(1q_pdl > si::force<si::newton>(0.138254) &&
|
||||
1q_pdl < si::force<si::newton>(0.138256));
|
||||
static_assert(1q_ft_pdl > si::energy<si::joule>(0.042140110093804) &&
|
||||
1q_ft_pdl < si::energy<si::joule>(0.042140110093806));
|
||||
static_assert(1q_ft_pdl_per_s > si::power<si::watt>(0.042140110093804) &&
|
||||
1q_ft_pdl_per_s < si::power<si::watt>(0.042140110093806));
|
||||
static_assert(1q_pdl_per_ft2> si::pressure<si::pascal>(1.4881639435) &&
|
||||
1q_pdl_per_ft2 < si::pressure<si::pascal>(1.4881639437));
|
||||
}
|
||||
|
||||
namespace fps_plus_si_literals {
|
||||
@ -112,16 +113,17 @@ static_assert(1q_ft == 0.3048q_m);
|
||||
static_assert(1q_lb == 0.45359237q_kg);
|
||||
static_assert(1q_s == 1q_s);
|
||||
static_assert(1q_ft_per_s == 0.3048q_m_per_s);
|
||||
static_assert(1q_ft2 == 0.09290304q_m2);
|
||||
static_assert(1q_ft2 > 0.09290303q_m2 &&
|
||||
1q_ft2 < 0.09290305q_m2);
|
||||
static_assert(1q_ft_per_s2 == 0.3048q_m_per_s2);
|
||||
static_assert(1q_pdl >= 0.138254q_N &&
|
||||
1q_pdl <= 0.138256q_N);
|
||||
static_assert(1q_ft_pdl >= 0.042140110093804q_J &&
|
||||
1q_ft_pdl <= 0.042140110093806q_J);
|
||||
static_assert(1q_ft_pdl_per_s >= 0.042140110093804q_W &&
|
||||
1q_ft_pdl_per_s <= 0.042140110093806q_W);
|
||||
static_assert(1q_pdl_per_ft2>= 1.4881639435q_Pa &&
|
||||
1q_pdl_per_ft2 <=1.4881639437q_Pa);
|
||||
static_assert(1q_pdl > 0.138254q_N &&
|
||||
1q_pdl < 0.138256q_N);
|
||||
static_assert(1q_ft_pdl > 0.042140110093804q_J &&
|
||||
1q_ft_pdl < 0.042140110093806q_J);
|
||||
static_assert(1q_ft_pdl_per_s > 0.042140110093804q_W &&
|
||||
1q_ft_pdl_per_s < 0.042140110093806q_W);
|
||||
static_assert(1q_pdl_per_ft2 > 1.4881639435q_Pa &&
|
||||
1q_pdl_per_ft2 < 1.4881639437q_Pa);
|
||||
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,7 @@ static_assert(10q_Hz * 1q_min == 600);
|
||||
static_assert(2 / 1q_Hz == 2q_s);
|
||||
|
||||
// force
|
||||
|
||||
static_assert(10q_kg * 10q_m_per_s2 == 100q_N);
|
||||
static_assert(100q_N / 1q_m_per_s2 == 100q_kg);
|
||||
static_assert(100q_N / 1q_kg == 100q_m_per_s2);
|
||||
@ -237,8 +238,6 @@ static_assert(kilogray::symbol == "kGy");
|
||||
|
||||
// speed
|
||||
|
||||
static_assert(is_same_v<decltype(1q_km / 1q_s), speed<scaled_unit<ratio(1, 1, 3), metre_per_second>, std::int64_t>>);
|
||||
|
||||
static_assert(10q_m / 5q_s == 2q_m_per_s);
|
||||
static_assert(10 / 5q_s * 1q_m == 2q_m_per_s);
|
||||
static_assert(1q_km / 1q_s == 1000q_m_per_s);
|
||||
|
@ -21,6 +21,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "units/unit.h"
|
||||
#include "units/bits/equivalent.h"
|
||||
#include "units/physical/si/prefixes.h"
|
||||
|
||||
namespace {
|
||||
@ -28,6 +29,9 @@ namespace {
|
||||
using namespace units;
|
||||
using namespace units::physical;
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare = DOWNCAST_MODE != 0 ? std::is_same_v<T, U> : (std::is_same_v<T, U> || units::equivalent<T, U>);
|
||||
|
||||
struct metre : named_unit<metre, "m", si::prefix> {};
|
||||
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
||||
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
||||
@ -46,11 +50,11 @@ struct metre_per_second : unit<metre_per_second> {};
|
||||
struct dim_speed : derived_dimension<dim_speed, metre_per_second, units::exp<dim_length, 1>, units::exp<dim_time, -1>> {};
|
||||
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
|
||||
|
||||
static_assert(is_same_v<downcast<scaled_unit<ratio(1), metre>>, metre>);
|
||||
static_assert(is_same_v<downcast<scaled_unit<ratio(1, 1, -2), metre>>, centimetre>);
|
||||
static_assert(is_same_v<downcast<scaled_unit<ratio(yard::ratio.num, yard::ratio.den, yard::ratio.exp), metre>>, yard>);
|
||||
static_assert(is_same_v<downcast<scaled_unit<yard::ratio * ratio(1, 3), metre>>, foot>);
|
||||
static_assert(is_same_v<downcast<scaled_unit<kilometre::ratio / hour::ratio, metre_per_second>>, kilometre_per_hour>);
|
||||
static_assert(compare<downcast<scaled_unit<ratio(1), metre>>, metre>);
|
||||
static_assert(compare<downcast<scaled_unit<ratio(1, 1, -2), metre>>, centimetre>);
|
||||
static_assert(compare<downcast<scaled_unit<ratio(yard::ratio.num, yard::ratio.den, yard::ratio.exp), metre>>, yard>);
|
||||
static_assert(compare<downcast<scaled_unit<yard::ratio * ratio(1, 3), metre>>, foot>);
|
||||
static_assert(compare<downcast<scaled_unit<kilometre::ratio / hour::ratio, metre_per_second>>, kilometre_per_hour>);
|
||||
|
||||
static_assert(centimetre::symbol == "cm");
|
||||
static_assert(kilometre::symbol == "km");
|
||||
|
Reference in New Issue
Block a user