Merge branch 'master' into feature/more-value-casts

This commit is contained in:
Mateusz Pusz
2024-06-14 21:44:19 +09:00
committed by GitHub
102 changed files with 1293 additions and 1021 deletions

View File

@ -5,11 +5,12 @@
### 2.2.0 <small>WIP</small> { id="2.2.0" }
- (!) feat: C++ modules support added by [@JohelEGP](https://github.com/JohelEGP)
- (!) feat: formatting grammar improved and units formatting support added
- (!) feat: New formatting specification implemented
- (!) feat: `has_unit_symbol` support removed
- (!) feat: ABI concerns resolved with introduction of u8 strings for symbols
- (!) feat: API-related Conan, CMake, and preprocessor options redesigned
- (!) feat: :boom: `core.h` removed
- (!) feat: `core.h` removed
- (!) feat: from now on units, dimensions, quantity specifications, and point origins have to be marked as `final`
- feat: implicit point origins support added
- feat: unit default point origin support added
- feat: `fma`, `isfinite`, `isinf`, and `isnan` math function added by [@NAThompson](https://github.com/NAThompson)
@ -29,10 +30,10 @@
- feat: unit text output support added
- feat: formatting error messages improved
- feat: improve types readability by eliminating extraneous `()` in references, prefixes, and `kind_of`
- feat: dimension text output added
- feat: dimension and unit text output added
- feat: some light and radiation ISQ quantities added
- feat: New formatting specification implemented
- feat: allow configuring GSL library use
- feat: freestanding support added
- (!) refactor: `zero_Fahrenheit` renamed to `zeroth_degree_Fahrenheit`
- (!) refactor: SI-related trigonometric functions moved to the `si` subnamespace
- (!) refactor: `math.h` header file broke up to smaller pieces
@ -47,6 +48,9 @@
- (!) refactor: `framework.h` introduced
- (!) refactor: type list tools made an implementation detail of the library
- (!) refactor: header files with the entire system definitions moved up in the directory tree
- (!) refactor: `absolute_point_origin` does not use CRTP anymore
- refactor: system's units do not inherit from one another anymore
- refactor: all units made `final`
- refactor: math functions constraints refactored
- refactor: `si_quantities.h` added to improve compile-times
- refactor: `validate_ascii_string` refactored to `is_basic_literal_character_set`
@ -54,6 +58,8 @@
- refactor: code refactored to comply with clang-tidy
- refactor: remove dependency on `<ranges>` header and switch to use an iterator-based `copy` algorithm
- refactor: `terminate` replaced with `abort` and a header file added
- refactor: most `std::remove_const_t` removed and some replaced with the GCC-specific workaround
- refactor: not needed `remove_reference_t` and `remove_cvref_t` removed
- fix: `QuantityLike` conversions required `Q::rep` instead of using one provided by `quantity_like_traits`
- fix: `QuantitySpec[Unit]` replaced with `make_reference` in `value_cast`
- fix: `ice_point` is now defined with the integral offset from `absolute_zero`
@ -82,6 +88,7 @@
- docs: "Text Output" chapter updated with the recent formatting changes
- docs: formatting grammar language changed to EBNF
- docs: "Project structure" chapter expanded
- docs: CITATION.cff updated
- (!) build: Conan and CMake options refactored
- (!) build: `MP_UNITS_AS_SYSTEM_HEADERS` renamed to `MP_UNITS_BUILD_AS_SYSTEM_HEADERS`
- (!) build: `MP_UNITS_BUILD_LA` and `MP_UNITS_IWYU` CMake options now have `_DEV_` in the name
@ -97,6 +104,7 @@
- build(conan): `can_run` check added before running tests
- ci: Conan and CMake CI now use different cache names
- ci: gcc-14 added
- ci: `clang-tidy` CI added
### 2.1.1 <small>May 16, 2024</small> { id="2.1.1" }

View File

@ -207,12 +207,13 @@ class MPUnitsConan(ConanFile):
self.version = version.strip()
def requirements(self):
if self.options.contracts == "gsl-lite":
self.requires("gsl-lite/0.41.0")
elif self.options.contracts == "ms-gsl":
self.requires("ms-gsl/4.0.0")
if self._use_fmtlib and not self.options.freestanding:
self.requires("fmt/10.2.1")
if not self.options.freestanding:
if self.options.contracts == "gsl-lite":
self.requires("gsl-lite/0.41.0")
elif self.options.contracts == "ms-gsl":
self.requires("ms-gsl/4.0.0")
if self._use_fmtlib:
self.requires("fmt/10.2.1")
def build_requirements(self):
if self._build_all:
@ -248,9 +249,12 @@ class MPUnitsConan(ConanFile):
tc.cache_variables["MP_UNITS_BUILD_CXX_MODULES"] = str(
self.options.cxx_modules
).upper()
tc.cache_variables["MP_UNITS_API_STD_FORMAT"] = str(
self.options.std_format
).upper()
if self.options.freestanding:
tc.cache_variables["MP_UNITS_API_FREESTANDING"] = True
else:
tc.cache_variables["MP_UNITS_API_STD_FORMAT"] = str(
self.options.std_format
).upper()
tc.cache_variables["MP_UNITS_API_STRING_VIEW_RET"] = str(
self.options.string_view_ret
).upper()
@ -258,7 +262,6 @@ class MPUnitsConan(ConanFile):
tc.cache_variables["MP_UNITS_API_CONTRACTS"] = str(
self.options.contracts
).upper()
tc.cache_variables["MP_UNITS_API_FREESTANDING"] = self.options.freestanding
tc.generate()
deps = CMakeDeps(self)
deps.generate()
@ -285,13 +288,39 @@ class MPUnitsConan(ConanFile):
def package_info(self):
compiler = self.settings.compiler
self.cpp_info.components["core"]
if self.options.contracts == "gsl-lite":
self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"]
# handle contracts
if self.options.contracts == "none":
self.cpp_info.components["core"].defines.append("MP_UNITS_API_CONTRACTS=0")
elif self.options.contracts == "gsl-lite":
self.cpp_info.components["core"].requires.append("gsl-lite::gsl-lite")
self.cpp_info.components["core"].defines.append("MP_UNITS_API_CONTRACTS=2")
elif self.options.contracts == "ms-gsl":
self.cpp_info.components["core"].requires = ["ms-gsl::ms-gsl"]
if self._use_fmtlib and not self.options.freestanding:
self.cpp_info.components["core"].requires.append("ms-gsl::ms-gsl")
self.cpp_info.components["core"].defines.append("MP_UNITS_API_CONTRACTS=3")
# handle API options
if self.options.string_view_ret != "auto":
self.cpp_info.components["core"].defines.append(
"MP_UNITS_API_STRING_VIEW_RET="
+ str(int(self.options.string_view_ret == True))
)
if self.options.no_crtp != "auto":
self.cpp_info.components["core"].defines.append(
"MP_UNITS_API_NO_CRTP=" + str(int(self.options.no_crtp == True))
)
if self.options.std_format != "auto":
self.cpp_info.components["core"].defines.append(
"MP_UNITS_API_STD_FORMAT=" + str(int(self.options.std_format == True))
)
if self._use_fmtlib:
self.cpp_info.components["core"].requires.append("fmt::fmt")
# handle hosted configuration
if not self.options.freestanding:
self.cpp_info.components["core"].defines.append("MP_UNITS_HOSTED=1")
if compiler == "msvc":
self.cpp_info.components["core"].cxxflags = ["/utf-8"]
self.cpp_info.components["systems"].requires = ["core"]

View File

@ -172,7 +172,7 @@ Additionally, some CMake options were renamed to better express the impact on ou
Before this release, the library always depended on [gsl-lite](https://github.com/gsl-lite/gsl-lite)
to perform runtime contract and asserts checking. In this release we introduced new options
to control if contract checking should be based on [gsl-lite](https://github.com/gsl-lite/gsl-lite),
[ms-gsl](https://github.com/microsoft/GSL), or maybe completely disabled.
[ms-gsl](https://github.com/microsoft/GSL), or may be completely disabled.
## Freestanding support
@ -205,7 +205,7 @@ origins. For example:
=== "Before"
```cpp
constexpr struct zero : absolute_point_origin<zero, currency> {} zero;
constexpr struct zero final : absolute_point_origin<currency> {} zero;
quantity_point price_usd = zero + 100 * USD;
```
@ -260,6 +260,16 @@ named with its corresponding unit and with the `si::zeroth_degree_Celsius`
## Changes to units definitions
There were several known issues when units were deriving from each other
(e.g., [#512](https://github.com/mpusz/mp-units/issues/512) and
[#537](https://github.com/mpusz/mp-units/issues/537)). We could either highly complicate the
framework to allow these which could result in much longer compilation times or disallow inheriting
from units at all. We chose the second option.
With this release all of of the units must be marked as `final`. To enforce this we have changed
the definition of the `Unit<T>` concept, which now requires type `T` to be `final`
(:boom: **breaking change** :boom:).
[WG21 Study Group 16 (Unicode) raised concerns](https://github.com/sg16-unicode/sg16-meetings#january-24th-2024)
about potential ABI issues when different translation units are compiled with different ordinary
literal encodings. Those issues were resolved with a change to units definitions
@ -272,7 +282,7 @@ is why it was renamed to `symbol_text` (:boom: **breaking change** :boom:).
=== "Now"
```cpp
inline constexpr struct ohm : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct ohm final : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```
=== "Before"
@ -286,9 +296,48 @@ is why it was renamed to `symbol_text` (:boom: **breaking change** :boom:).
On C++20-compliant compilers it should be enough to type the following in the unit's definition:
```cpp
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct ohm final : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```
## Changes to dimension, quantity specification, and point origins definitions
Similarly to units, now also all dimensions, quantity specifications, and point origins have to be
marked `final` (:boom: **breaking change** :boom:).
=== "Now"
```cpp
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr auto zeroth_kelvin = absolute_zero;
inline constexpr struct kelvin final : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
inline constexpr struct ice_point final : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr auto zeroth_degree_Celsius = ice_point;
inline constexpr struct degree_Celsius final : named_unit<symbol_text{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
```
=== "Before"
```cpp
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
inline constexpr struct kelvin : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
inline constexpr struct ice_point : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
inline constexpr struct degree_Celsius : named_unit<symbol_text{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
```
Please also note, that the `absolute_point_origin` does not use CRTP idiom anymore (:boom: **breaking change** :boom:).
## Improved text output
With this release, we can print not only whole quantities but also just their units or dimensions.
@ -461,8 +510,8 @@ conversion factor. Here is a comparison of the code with previous and current de
=== "Now"
```cpp
inline constexpr struct yard : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct foot : named_unit<"ft", mag_ratio<1, 3> * yard> {} foot;
inline constexpr struct yard final : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct foot final : named_unit<"ft", mag_ratio<1, 3> * yard> {} foot;
```
=== "Before"

View File

@ -342,7 +342,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`MP_UNITS_API_STD_FORMAT`](#MP_UNITS_API_STD_FORMAT){ #MP_UNITS_API_STD_FORMAT }
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `AUTO`/`TRUE`/`FALSE` (Default: `AUTO`)
Enables the usage of [`std::format`](https://en.cppreference.com/w/cpp/utility/format/format)
and associated facilities for text formatting. If it is not supported, then
@ -352,7 +352,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`MP_UNITS_API_STRING_VIEW_RET`](#MP_UNITS_API_STRING_VIEW_RET){ #MP_UNITS_API_STRING_VIEW_RET }
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `AUTO`/`TRUE`/`FALSE` (Default: `AUTO`)
Enables returning `std::string_view` from the
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
@ -364,7 +364,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`MP_UNITS_API_NO_CRTP`](#MP_UNITS_API_NO_CRTP){ #MP_UNITS_API_NO_CRTP }
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `AUTO`/`TRUE`/`FALSE` (Default: `AUTO`)
Removes the need for the usage of the CRTP idiom in the
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).

View File

@ -33,7 +33,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
using namespace mp_units;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
inline constexpr struct smoot final : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
int main()
{
@ -53,7 +53,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
using namespace mp_units;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
inline constexpr struct smoot final : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
int main()
{
@ -69,7 +69,7 @@ Output:
Harvard Bridge length = 364.4 smoot (2034.6 ft, 620.14 m) ± 1 εar
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/zsW1f6Tn1)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/f8f4KnKh8)"
??? question "What is `smoot`?"

View File

@ -7,7 +7,7 @@ tags:
# `avg_speed`
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/EYo7879qd)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/TnqGa4sdn)"
Let's continue the previous example. This time, our purpose will not be to showcase as many
library features as possible, but we will scope on different interfaces one can provide

View File

@ -6,7 +6,7 @@ tags:
# `hello_units`
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/KKGGhKjqn)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/bT4GGPbef)"
This is a really simple example showcasing the features of the **mp-units** library.
@ -18,20 +18,20 @@ First, we either import the `mp_units` module or include the headers for:
- text formatting and stream output support
```cpp title="hello_units.cpp" linenums="1"
--8<-- "example/hello_units.cpp:28:40"
--8<-- "example/hello_units.cpp:28:41"
```
Also, to shorten the definitions, we "import" all the symbols from the `mp_units` namespace.
```cpp title="hello_units.cpp" linenums="13"
--8<-- "example/hello_units.cpp:41:42"
```cpp title="hello_units.cpp" linenums="14"
--8<-- "example/hello_units.cpp:42:43"
```
Next, we define a simple function that calculates the average speed based on the provided
arguments of length and time:
```cpp title="hello_units.cpp" linenums="14"
--8<-- "example/hello_units.cpp:43:46"
```cpp title="hello_units.cpp" linenums="15"
--8<-- "example/hello_units.cpp:44:47"
```
The above function template takes any quantities implicitly convertible to `isq::length`
@ -45,37 +45,37 @@ that its quantity type is implicitly convertible to `isq::speed`.
type is beneficial for users of such a function as it provides more information
of what to expect from a function than just using `auto`.
```cpp title="hello_units.cpp" linenums="18"
--8<-- "example/hello_units.cpp:48:51"
```cpp title="hello_units.cpp" linenums="19"
--8<-- "example/hello_units.cpp:49:52"
```
The above lines explicitly opt into using unit symbols from two systems of units.
As this introduces a lot of short identifiers into the current scope, it is not done
implicitly while including a header file.
```cpp title="hello_units.cpp" linenums="22"
--8<-- "example/hello_units.cpp:53:59"
```cpp title="hello_units.cpp" linenums="23"
--8<-- "example/hello_units.cpp:54:60"
```
- Lines `21` & `22` create a quantity of kind `isq::length / isq::time` with the numbers
- Lines `23` & `24` create a quantity of kind `isq::length / isq::time` with the numbers
and units provided. Such quantities can be converted or assigned to any other quantity
with a matching kind.
- Line `23` calls our function template with quantities of kind `isq::length` and
- Line `25` calls our function template with quantities of kind `isq::length` and
`isq::time` and number and units provided.
- Line `24` explicitly provides quantity types of the quantities passed to a function template.
- Line `26` explicitly provides quantity types of the quantities passed to a function template.
This time, those will not be quantity kinds anymore and will have
[more restrictive conversion rules](../framework_basics/simple_and_typed_quantities.md#quantity_cast-to-force-unsafe-conversions).
- Line `25` changes the unit of a quantity `v3` to `m / s` in a
- Line `27` changes the unit of a quantity `v3` to `m / s` in a
[value-preserving way](../framework_basics/value_conversions.md#value-preserving-conversions)
(floating-point representations are considered to be value-preserving).
- Line `26` does a similar operation, but this time, it would also succeed for
- Line `28` does a similar operation, but this time, it would also succeed for
[value-truncating cases](../framework_basics/value_conversions.md#value-truncating-conversions)
(if that was the case).
- Line `27` does a [value-truncating conversion](../framework_basics/value_conversions.md#value-truncating-conversions)
- Line `29` does a [value-truncating conversion](../framework_basics/value_conversions.md#value-truncating-conversions)
of changing the underlying representation type from `double` to `int`.
```cpp title="hello_units.cpp" linenums="29"
--8<-- "example/hello_units.cpp:61"
```cpp title="hello_units.cpp" linenums="30"
--8<-- "example/hello_units.cpp:62"
```
The above presents [various ways to print a quantity](../framework_basics/text_output.md).

View File

@ -6,14 +6,14 @@ tags:
# `si_constants`
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/sEqWcchdE)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/MevcK8vYT)"
The next example presents all the seven defining constants of the SI system. We can observe
how [Faster-than-lightspeed Constants](../framework_basics/faster_than_lightspeed_constants.md)
work in practice.
```cpp title="si_constants.cpp" linenums="1"
--8<-- "example/si_constants.cpp:28:39"
--8<-- "example/si_constants.cpp:28:40"
```
As always, we start with the inclusion of all the needed header files. After that, for
@ -21,8 +21,8 @@ the simplicity of this example, we
[hack the character of quantities](../framework_basics/character_of_a_quantity.md#hacking-the-character)
to be able to express vector quantities with simple scalar types.
```cpp title="si_constants.cpp" linenums="13"
--8<-- "example/si_constants.cpp:41:"
```cpp title="si_constants.cpp" linenums="14"
--8<-- "example/si_constants.cpp:42:"
```
The main part of the example prints all of the SI-defining constants. While analyzing the output of

View File

@ -97,15 +97,15 @@ enumeration can be appended to the `quantity_spec` describing such a quantity ty
=== "C++23"
```cpp
inline constexpr struct position_vector : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<length, quantity_character::vector> {} displacement;
inline constexpr struct position_vector final : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<length, quantity_character::vector> {} displacement;
```
=== "C++20"
```cpp
inline constexpr struct position_vector : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
inline constexpr struct position_vector final : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
```
=== "Portable"
@ -126,13 +126,13 @@ character override is needed):
=== "C++23"
```cpp
inline constexpr struct velocity : quantity_spec<speed, position_vector / duration> {} velocity;
inline constexpr struct velocity final : quantity_spec<speed, position_vector / duration> {} velocity;
```
=== "C++20"
```cpp
inline constexpr struct velocity : quantity_spec<velocity, speed, position_vector / duration> {} velocity;
inline constexpr struct velocity final : quantity_spec<velocity, speed, position_vector / duration> {} velocity;
```
=== "Portable"

View File

@ -16,6 +16,8 @@ or derived [quantity](../../appendix/glossary.md#quantity):
by the library's framework based on the [quantity equation](../../appendix/glossary.md#quantity-equation)
provided in the [quantity specification](../../appendix/glossary.md#quantity_spec).
All of the above dimensions have to be marked as `final`.
### `DimensionOf<T, V>` { #DimensionOf }
@ -42,6 +44,8 @@ including:
- Intermediate [derived quantity](../../appendix/glossary.md#derived-quantity) specifications being
a result of a [quantity equations](../../appendix/glossary.md#quantity-equation) on other specifications.
All of the above quantity specifications have to be marked as `final`.
### `QuantitySpecOf<T, V>` { #QuantitySpecOf }
@ -84,6 +88,8 @@ and when `T` is implicitly convertible to `V`.
- [Derived unnamed units](../../appendix/glossary.md#derived-unit) being a result of a
[unit equations](../../appendix/glossary.md#unit-equation) on other units.
All of the above units have to be marked as `final`.
!!! note
In the **mp-units** library, [physical constants are also implemented as units](faster_than_lightspeed_constants.md).
@ -235,7 +241,7 @@ implicitly convertible from quantity specification `V`, which means that `V` mus
However, if we define `mean_sea_level` in the following way:
```cpp
inline constexpr struct mean_sea_level : absolute_point_origin<isq::altitude> {} mean_sea_level;
inline constexpr struct mean_sea_level final : absolute_point_origin<isq::altitude> {} mean_sea_level;
```
then it can't be used as a point origin for _points_ of `isq::length` or `isq::width` as none of them
@ -328,7 +334,7 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
using T = std::chrono::time_point<C, std::chrono::seconds>;
static constexpr auto reference = si::second;
static constexpr struct point_origin : absolute_point_origin<isq::time> {} point_origin{};
static constexpr struct point_origin final : absolute_point_origin<isq::time> {} point_origin{};
using rep = std::chrono::seconds::rep;
[[nodiscard]] static constexpr convert_implicitly<quantity<reference, rep>> to_quantity(const T& qp)

View File

@ -60,8 +60,8 @@ For example:
the following way:
```cpp
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
```
[Derived dimensions](../../appendix/glossary.md#derived-dimension) are implicitly created
@ -71,9 +71,9 @@ provided in the [quantity specification](../../appendix/glossary.md#quantity_spe
=== "C++23"
```cpp
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct time : quantity_spec<dim_time> {} time;
inline constexpr struct speed : quantity_spec<length / time> {} speed;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct time final : quantity_spec<dim_time> {} time;
inline constexpr struct speed final : quantity_spec<length / time> {} speed;
static_assert(speed.dimension == dim_length / dim_time);
```
@ -81,9 +81,9 @@ provided in the [quantity specification](../../appendix/glossary.md#quantity_spe
=== "C++20"
```cpp
inline constexpr struct length : quantity_spec<length, dim_length> {} length;
inline constexpr struct time : quantity_spec<time, dim_time> {} time;
inline constexpr struct speed : quantity_spec<speed, length / time> {} speed;
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct time final : quantity_spec<time, dim_time> {} time;
inline constexpr struct speed final : quantity_spec<speed, length / time> {} speed;
static_assert(speed.dimension == dim_length / dim_time);
```
@ -183,17 +183,17 @@ Quantity specification can be defined by the user in one of the following ways:
=== "C++23"
```cpp
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct height : quantity_spec<length> {} height;
inline constexpr struct speed : quantity_spec<length / time> {} speed;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct height final : quantity_spec<length> {} height;
inline constexpr struct speed final : quantity_spec<length / time> {} speed;
```
=== "C++20"
```cpp
inline constexpr struct length : quantity_spec<length, dim_length> {} length;
inline constexpr struct height : quantity_spec<height, length> {} height;
inline constexpr struct speed : quantity_spec<speed, length / time> {} speed;
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct height final : quantity_spec<height, length> {} height;
inline constexpr struct speed final : quantity_spec<speed, length / time> {} speed;
```
=== "Portable"
@ -234,13 +234,13 @@ A unit can be defined by the user in one of the following ways:
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
template<PrefixableUnit auto U> inline constexpr kilo_<decltype(U)> kilo;
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct minute final : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct gram final : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr auto kilogram = kilo<gram>;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct speed_of_light_in_vacuum : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct speed_of_light_in_vacuum final : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
```
The [unit equation](../../appendix/glossary.md#unit-equation) of `si::metre / si::second` results
@ -346,13 +346,13 @@ For example:
- the absolute point origin can be defined in the following way:
```cpp
inline constexpr struct absolute_zero : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
```
- the relative point origin can be defined in the following way:
```cpp
inline constexpr struct ice_point : relative_point_origin<absolute_zero + 273'150 * milli<kelvin>> {} ice_point;
inline constexpr struct ice_point final : relative_point_origin<absolute_zero + 273'150 * milli<kelvin>> {} ice_point;
```

View File

@ -113,7 +113,7 @@ that uses a unit that is proportional to the ratio of kilometers per megaparsecs
units of _length_:
```cpp
inline constexpr struct hubble_constant :
inline constexpr struct hubble_constant final :
named_unit<{u8"H₀", "H_0"}, mag_ratio<701, 10> * si::kilo<si::metre> / si::second / si::mega<parsec>> {} hubble_constant;
```
@ -158,9 +158,9 @@ Besides the unit `one`, there are a few other scaled units predefined in the lib
with dimensionless quantities:
```cpp
inline constexpr struct percent : named_unit<"%", mag_ratio<1, 100> * one> {} percent;
inline constexpr struct per_mille : named_unit<{u8"‰", "%o"}, mag_ratio<1, 1000> * one> {} per_mille;
inline constexpr struct parts_per_million : named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {} parts_per_million;
inline constexpr struct percent final : named_unit<"%", mag_ratio<1, 100> * one> {} percent;
inline constexpr struct per_mille final : named_unit<{u8"‰", "%o"}, mag_ratio<1, 1000> * one> {} per_mille;
inline constexpr struct parts_per_million final : named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {} parts_per_million;
inline constexpr auto ppm = parts_per_million;
```
@ -217,17 +217,17 @@ to the quantity specification:
=== "C++23"
```cpp
inline constexpr struct angular_measure : quantity_spec<dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure : quantity_spec<dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity : quantity_spec<dimensionless, is_kind> {} storage_capacity;
inline constexpr struct angular_measure final : quantity_spec<dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure final : quantity_spec<dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity final : quantity_spec<dimensionless, is_kind> {} storage_capacity;
```
=== "C++20"
```cpp
inline constexpr struct angular_measure : quantity_spec<angular_measure, dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure : quantity_spec<solid_angular_measure, dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity : quantity_spec<storage_capacity, dimensionless, is_kind> {} storage_capacity;
inline constexpr struct angular_measure final : quantity_spec<angular_measure, dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure final : quantity_spec<solid_angular_measure, dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity final : quantity_spec<storage_capacity, dimensionless, is_kind> {} storage_capacity;
```
=== "Portable"
@ -242,9 +242,9 @@ With the above, we can constrain `radian`, `steradian`, and `bit` to be allowed
specific quantity kinds only:
```cpp
inline constexpr struct radian : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct bit : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
inline constexpr struct radian final : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian final : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct bit final : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
```
but still allow the usage of `one` and its scaled versions for such quantities.

View File

@ -39,12 +39,12 @@ namespace si {
namespace si2019 {
inline constexpr struct speed_of_light_in_vacuum :
inline constexpr struct speed_of_light_in_vacuum final :
named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
} // namespace si2019
inline constexpr struct magnetic_constant :
inline constexpr struct magnetic_constant final :
named_unit<{u8"μ₀", "u_0"}, mag<4> * mag_pi * mag_power<10, -7> * henry / metre> {} magnetic_constant;
} // namespace mp_units::si

View File

@ -6,8 +6,8 @@ The **mp-units** library decided to use a rather unusual pattern to define entit
Here is how we define `metre` and `second` [SI](../../appendix/glossary.md#si) base units:
```cpp
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
```
Please note that the above reuses the same identifier for a type and its value. The rationale
@ -94,9 +94,9 @@ the value-based [unit equation](../../appendix/glossary.md#unit-equation) to a c
definition:
```cpp
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct pascal : named_unit<"Pa", newton / square(metre)> {} pascal;
inline constexpr struct joule : named_unit<"J", newton * metre> {} joule;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct pascal final : named_unit<"Pa", newton / square(metre)> {} pascal;
inline constexpr struct joule final : named_unit<"J", newton * metre> {} joule;
```

View File

@ -316,13 +316,13 @@ Let's see another example:
using namespace mp_units;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
: quantity_spec<isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final :
quantity_spec<isq::length> {} horizontal_length;
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
inline constexpr struct horizontal_area final :
quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[square(si::metre)]> base_;
@ -429,13 +429,13 @@ Let's see another example:
using namespace mp_units;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
: quantity_spec<isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final :
quantity_spec<isq::length> {} horizontal_length;
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
inline constexpr struct horizontal_area final :
quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[square(si::metre)]> base_;

View File

@ -148,45 +148,45 @@ For example, here is how the above quantity kind tree can be modeled in the libr
=== "C++23"
```cpp
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct width : quantity_spec<length> {} width;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct width final : quantity_spec<length> {} width;
inline constexpr auto breadth = width;
inline constexpr struct height : quantity_spec<length> {} height;
inline constexpr struct height final : quantity_spec<length> {} height;
inline constexpr auto depth = height;
inline constexpr auto altitude = height;
inline constexpr struct thickness : quantity_spec<width> {} thickness;
inline constexpr struct diameter : quantity_spec<width> {} diameter;
inline constexpr struct radius : quantity_spec<width> {} radius;
inline constexpr struct radius_of_curvature : quantity_spec<radius> {} radius_of_curvature;
inline constexpr struct path_length : quantity_spec<length> {} path_length;
inline constexpr struct thickness final : quantity_spec<width> {} thickness;
inline constexpr struct diameter final : quantity_spec<width> {} diameter;
inline constexpr struct radius final : quantity_spec<width> {} radius;
inline constexpr struct radius_of_curvature final : quantity_spec<radius> {} radius_of_curvature;
inline constexpr struct path_length final : quantity_spec<length> {} path_length;
inline constexpr auto arc_length = path_length;
inline constexpr struct distance : quantity_spec<path_length> {} distance;
inline constexpr struct radial_distance : quantity_spec<distance> {} radial_distance;
inline constexpr struct wavelength : quantity_spec<length> {} wavelength;
inline constexpr struct position_vector : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<length, quantity_character::vector> {} displacement;
inline constexpr struct distance final : quantity_spec<path_length> {} distance;
inline constexpr struct radial_distance final : quantity_spec<distance> {} radial_distance;
inline constexpr struct wavelength final : quantity_spec<length> {} wavelength;
inline constexpr struct position_vector final : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<length, quantity_character::vector> {} displacement;
```
=== "C++20"
```cpp
inline constexpr struct length : quantity_spec<length, dim_length> {} length;
inline constexpr struct width : quantity_spec<width, length> {} width;
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct width final : quantity_spec<width, length> {} width;
inline constexpr auto breadth = width;
inline constexpr struct height : quantity_spec<height, length> {} height;
inline constexpr struct height final : quantity_spec<height, length> {} height;
inline constexpr auto depth = height;
inline constexpr auto altitude = height;
inline constexpr struct thickness : quantity_spec<thickness, width> {} thickness;
inline constexpr struct diameter : quantity_spec<diameter, width> {} diameter;
inline constexpr struct radius : quantity_spec<radius, width> {} radius;
inline constexpr struct radius_of_curvature : quantity_spec<radius_of_curvature, radius> {} radius_of_curvature;
inline constexpr struct path_length : quantity_spec<path_length, length> {} path_length;
inline constexpr struct thickness final : quantity_spec<thickness, width> {} thickness;
inline constexpr struct diameter final : quantity_spec<diameter, width> {} diameter;
inline constexpr struct radius final : quantity_spec<radius, width> {} radius;
inline constexpr struct radius_of_curvature final : quantity_spec<radius_of_curvature, radius> {} radius_of_curvature;
inline constexpr struct path_length final : quantity_spec<path_length, length> {} path_length;
inline constexpr auto arc_length = path_length;
inline constexpr struct distance : quantity_spec<distance, path_length> {} distance;
inline constexpr struct radial_distance : quantity_spec<radial_distance, distance> {} radial_distance;
inline constexpr struct wavelength : quantity_spec<wavelength, length> {} wavelength;
inline constexpr struct position_vector : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
inline constexpr struct distance final : quantity_spec<distance, path_length> {} distance;
inline constexpr struct radial_distance final : quantity_spec<radial_distance, distance> {} radial_distance;
inline constexpr struct wavelength final : quantity_spec<wavelength, length> {} wavelength;
inline constexpr struct position_vector final : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
```
=== "Portable"

View File

@ -26,7 +26,7 @@ this is expressed by associating a quantity kind (that we discussed in detail in
previous chapter) with a unit that is used to express it:
```cpp
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
```
!!! important
@ -67,7 +67,7 @@ of a specific predefined [unit equation](../../appendix/glossary.md#unit-equatio
For example, a unit of _power_ quantity is defined in the library as:
```cpp
inline constexpr struct watt : named_unit<"W", joule / second> {} watt;
inline constexpr struct watt final : named_unit<"W", joule / second> {} watt;
```
However, a _power_ quantity can be expressed in other units as well. For example,
@ -110,8 +110,8 @@ The library allows constraining such units to work only with quantities of a spe
the following way:
```cpp
inline constexpr struct hertz : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
inline constexpr struct becquerel : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
inline constexpr struct hertz final : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
inline constexpr struct becquerel final : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
```
With the above, `hertz` can only be used with _frequencies_, while `becquerel` should only be used with
@ -168,25 +168,25 @@ be explicitly expressed with predefined SI prefixes. Those include units like mi
electronvolt:
```cpp
inline constexpr struct minute : named_unit<"min", mag<60> * si::second> {} minute;
inline constexpr struct hour : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct electronvolt : named_unit<"eV", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * si::joule> {} electronvolt;
inline constexpr struct minute final : named_unit<"min", mag<60> * si::second> {} minute;
inline constexpr struct hour final : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct electronvolt final : named_unit<"eV", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * si::joule> {} electronvolt;
```
Also, units of other [systems of units](../../appendix/glossary.md#system-of-units) are often defined
in terms of scaled versions of the SI units. For example, the international yard is defined as:
```cpp
inline constexpr struct yard : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct yard final : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
```
For some units, a magnitude might also be irrational. The best example here is a `degree` which
is defined using a floating-point magnitude having a factor of the number π (Pi):
```cpp
inline constexpr struct mag_pi : magnitude<std::numbers::pi_v<long double>> {} mag_pi;
inline constexpr struct mag_pi final : magnitude<std::numbers::pi_v<long double>> {} mag_pi;
```
```cpp
inline constexpr struct degree : named_unit<{u8"°", "deg"}, mag_pi / mag<180> * si::radian> {} degree;
inline constexpr struct degree final : named_unit<{u8"°", "deg"}, mag_pi / mag<180> * si::radian> {} degree;
```

View File

@ -33,30 +33,30 @@ and units of derived quantities.
=== "Dimensions"
```cpp
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_electric_current : base_dimension<"I"> {} dim_electric_current;
inline constexpr struct dim_thermodynamic_temperature : base_dimension<{u8"Θ", "O"}> {} dim_thermodynamic_temperature;
inline constexpr struct dim_amount_of_substance : base_dimension<"N"> {} dim_amount_of_substance;
inline constexpr struct dim_luminous_intensity : base_dimension<"J"> {} dim_luminous_intensity;
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass final : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_electric_current final : base_dimension<"I"> {} dim_electric_current;
inline constexpr struct dim_thermodynamic_temperature final : base_dimension<{u8"Θ", "O"}> {} dim_thermodynamic_temperature;
inline constexpr struct dim_amount_of_substance final : base_dimension<"N"> {} dim_amount_of_substance;
inline constexpr struct dim_luminous_intensity final : base_dimension<"J"> {} dim_luminous_intensity;
```
=== "Units"
```cpp
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct gram final : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr auto kilogram = kilo<gram>;
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct joule : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt : named_unit<"W", joule / second> {} watt;
inline constexpr struct coulomb : named_unit<"C", ampere * second> {} coulomb;
inline constexpr struct volt : named_unit<"V", watt / ampere> {} volt;
inline constexpr struct farad : named_unit<"F", coulomb / volt> {} farad;
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct joule final : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt final : named_unit<"W", joule / second> {} watt;
inline constexpr struct coulomb final : named_unit<"C", ampere * second> {} coulomb;
inline constexpr struct volt final : named_unit<"V", watt / ampere> {} volt;
inline constexpr struct farad final : named_unit<"F", coulomb / volt> {} farad;
inline constexpr struct ohm final : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```
=== "Prefixes"
@ -75,13 +75,13 @@ and units of derived quantities.
=== "Constants"
```cpp
inline constexpr struct hyperfine_structure_transition_frequency_of_cs : named_unit<{u8"Δν_Cs", "dv_Cs"}, mag<9'192'631'770> * hertz> {} hyperfine_structure_transition_frequency_of_cs;
inline constexpr struct speed_of_light_in_vacuum : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct planck_constant : named_unit<"h", mag_ratio<662'607'015, 100'000'000> * mag_power<10, -34> * joule * second> {} planck_constant;
inline constexpr struct elementary_charge : named_unit<"e", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * coulomb> {} elementary_charge;
inline constexpr struct boltzmann_constant : named_unit<"k", mag_ratio<1'380'649, 1'000'000> * mag_power<10, -23> * joule / kelvin> {} boltzmann_constant;
inline constexpr struct avogadro_constant : named_unit<"N_A", mag_ratio<602'214'076, 100'000'000> * mag_power<10, 23> / mole> {} avogadro_constant;
inline constexpr struct luminous_efficacy : named_unit<"K_cd", mag<683> * lumen / watt> {} luminous_efficacy;
inline constexpr struct hyperfine_structure_transition_frequency_of_cs final : named_unit<{u8"Δν_Cs", "dv_Cs"}, mag<9'192'631'770> * hertz> {} hyperfine_structure_transition_frequency_of_cs;
inline constexpr struct speed_of_light_in_vacuum final : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct planck_constant final : named_unit<"h", mag_ratio<662'607'015, 100'000'000> * mag_power<10, -34> * joule * second> {} planck_constant;
inline constexpr struct elementary_charge final : named_unit<"e", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * coulomb> {} elementary_charge;
inline constexpr struct boltzmann_constant final : named_unit<"k", mag_ratio<1'380'649, 1'000'000> * mag_power<10, -23> * joule / kelvin> {} boltzmann_constant;
inline constexpr struct avogadro_constant final : named_unit<"N_A", mag_ratio<602'214'076, 100'000'000> * mag_power<10, 23> / mole> {} avogadro_constant;
inline constexpr struct luminous_efficacy final : named_unit<"K_cd", mag<683> * lumen / watt> {} luminous_efficacy;
```
!!! important
@ -105,7 +105,7 @@ and units of derived quantities.
template name to initialize it with two symbols:
```cpp
inline constexpr struct ohm : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct ohm final : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```

View File

@ -172,7 +172,7 @@ origin.
![affine_space_2](affine_space_2.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
inline constexpr struct origin : absolute_point_origin<origin, isq::distance> {} origin;
inline constexpr struct origin final : absolute_point_origin<isq::distance> {} origin;
// quantity_point<si::metre, origin> qp1{100 * m}; // Compile-time error
// quantity_point<si::metre, origin> qp2{120 * m}; // Compile-time error
@ -197,14 +197,6 @@ assert(origin - qp2 == -120 * m);
// assert(origin - origin == 0 * m); // Compile-time error
```
!!! info
The `absolute_point_origin` class template uses the CRTP idiom to enforce the uniqueness of
such a type. You should pass the type of a derived class as the first argument of the template
instantiation.
*[CRTP]: Curiously Recurring Template Parameter
We can't construct a quantity point directly from the quantity anymore when a custom, named origin
is used. To prevent potential safety and maintenance issues, we always need to
explicitly provide both a compatible origin and a quantity measured from it to construct a quantity
@ -249,8 +241,8 @@ type and unit is being used:
![affine_space_3](affine_space_3.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
inline constexpr struct origin1 : absolute_point_origin<origin1, isq::distance> {} origin1;
inline constexpr struct origin2 : absolute_point_origin<origin2, isq::distance> {} origin2;
inline constexpr struct origin1 final : absolute_point_origin<isq::distance> {} origin1;
inline constexpr struct origin2 final : absolute_point_origin<isq::distance> {} origin2;
quantity_point qp1 = origin1 + 100 * m;
quantity_point qp2 = origin2 + 120 * m;
@ -284,10 +276,10 @@ For such cases, relative point origins should be used:
![affine_space_4](affine_space_4.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
inline constexpr struct A : absolute_point_origin<A, isq::distance> {} A;
inline constexpr struct B : relative_point_origin<A + 10 * m> {} B;
inline constexpr struct C : relative_point_origin<B + 10 * m> {} C;
inline constexpr struct D : relative_point_origin<A + 30 * m> {} D;
inline constexpr struct A final : absolute_point_origin<isq::distance> {} A;
inline constexpr struct B final : relative_point_origin<A + 10 * m> {} B;
inline constexpr struct C final : relative_point_origin<B + 10 * m> {} C;
inline constexpr struct D final : relative_point_origin<A + 30 * m> {} D;
quantity_point qp1 = C + 100 * m;
quantity_point qp2 = D + 120 * m;
@ -392,17 +384,17 @@ point origins for this purpose:
```cpp
namespace si {
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr auto zeroth_kelvin = absolute_zero;
inline constexpr struct ice_point : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
inline constexpr struct ice_point final : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr auto zeroth_degree_Celsius = ice_point;
}
namespace usc {
inline constexpr struct zeroth_degree_Fahrenheit :
inline constexpr struct zeroth_degree_Fahrenheit final :
relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
}
@ -426,16 +418,16 @@ definitions:
```cpp
namespace si {
inline constexpr struct kelvin :
inline constexpr struct kelvin final :
named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
inline constexpr struct degree_Celsius :
inline constexpr struct degree_Celsius final :
named_unit<{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
}
namespace usc {
inline constexpr struct degree_Fahrenheit :
inline constexpr struct degree_Fahrenheit final :
named_unit<{u8"°F", "`F"}, mag_ratio<5, 9> * si::degree_Celsius,
zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
@ -481,7 +473,7 @@ the following way:
![affine_space_6](affine_space_6.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
constexpr struct room_reference_temp : relative_point_origin<quantity_point{21 * deg_C}> {} room_reference_temp;
constexpr struct room_reference_temp final : relative_point_origin<quantity_point{21 * deg_C}> {} room_reference_temp;
using room_temp = quantity_point<isq::Celsius_temperature[deg_C], room_reference_temp>;
constexpr auto step_delta = isq::Celsius_temperature(0.5 * deg_C);

View File

@ -85,11 +85,11 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
=== "C++23"
```cpp
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency : quantity_spec<dim_currency> {} currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency final : quantity_spec<dim_currency> {} currency;
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar final : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
namespace unit_symbols {
@ -105,11 +105,11 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
=== "C++20"
```cpp
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency : quantity_spec<currency, dim_currency> {} currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency final : quantity_spec<currency, dim_currency> {} currency;
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar final : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
namespace unit_symbols {
@ -125,11 +125,11 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
=== "Portable"
```cpp
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
QUANTITY_SPEC(currency, dim_currency);
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar final : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
namespace unit_symbols {

View File

@ -256,8 +256,8 @@ include the _mp-units/systems/si/chrono.h_ file to benefit from it. This file pr
to the `std::chrono` abstractions:
```cpp
inline constexpr struct ts_origin : relative_point_origin<chrono_point_origin<system_clock> + 1 * h> {} ts_origin;
inline constexpr struct my_origin : absolute_point_origin<my_origin, isq::time> {} my_origin;
inline constexpr struct ts_origin final : relative_point_origin<chrono_point_origin<system_clock> + 1 * h> {} ts_origin;
inline constexpr struct my_origin final : absolute_point_origin<isq::time> {} my_origin;
quantity_point qp1 = sys_seconds{1s};
auto tp1 = to_chrono_time_point(qp1); // OK

View File

@ -29,7 +29,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<isq::length> {} horizontal_length;
// ...
@ -45,7 +45,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
// ...
@ -65,7 +65,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
// ...
@ -85,7 +85,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
// ...
@ -96,6 +96,7 @@ your code using **mp-units**:
```cpp
#include <iostream>
#include <mp-units/ext/format.h>
#ifdef MP_UNITS_MODULES
#include <mp-units/compat_macros.h>
import mp_units;
@ -157,3 +158,30 @@ from additional features provided with the library).
This macro resolves to either the `std` or `fmt` namespace, depending on the value of
[MP_UNITS_API_STD_FORMAT](../../getting_started/installation_and_usage.md#MP_UNITS_API_STD_FORMAT)
CMake option.
To include the header files of the underlying text formatting framework, the following include
should be used:
```cpp
#include <mp-units/ext/format.h>
```
### Contracts
The mp-units library internally does contract checking by default. It can be disabled with a Conan
or CMake option. However, when enabled, it can use either [gsl-lite](https://github.com/gsl-lite/gsl-lite)
or [ms-gsl](https://github.com/microsoft/GSL). To write a code that is independent from the
underlying framework, the following preprocessor macros are exposed:
- `MP_UNITS_EXPECTS(expr)`
- `MP_UNITS_EXPECTS_DEBUG(expr)`
- `MP_UNITS_ASSERT(expr)`
- `MP_UNITS_ASSERT_DEBUG(expr)`
Their meaning is consistent with respective [gsl-lite](https://github.com/gsl-lite/gsl-lite?tab=readme-ov-file#contract-checking-configuration-macros).
Also, to include the header files of the underlying framework, the following include should be used:
```cpp
#include <mp-units/ext/contracts.h>
```

View File

@ -28,32 +28,12 @@ if(${projectPrefix}BUILD_CXX_MODULES)
target_compile_features(example_utils INTERFACE cxx_std_20)
target_compile_definitions(example_utils INTERFACE ${projectPrefix}MODULES)
target_include_directories(example_utils INTERFACE include)
target_link_libraries(example_utils INTERFACE mp-units-contracts)
endif()
add_library(example_utils-headers INTERFACE)
target_include_directories(example_utils-headers INTERFACE include)
if(${projectPrefix}API_CONTRACTS STREQUAL "NONE")
target_compile_definitions(mp-units-core INTERFACE ${projectPrefix}API_CONTRACTS=0)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "GSL-LITE")
if(NOT TARGET gsl::gsl-lite)
find_package(gsl-lite REQUIRED)
endif()
if(${projectPrefix}BUILD_CXX_MODULES)
target_link_libraries(example_utils INTERFACE gsl::gsl-lite)
endif()
target_link_libraries(example_utils-headers INTERFACE gsl::gsl-lite)
target_compile_definitions(mp-units-core INTERFACE ${projectPrefix}API_CONTRACTS=2)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "MS-GSL")
if(NOT TARGET Microsoft.GSL::GSL)
find_package(Microsoft.GSL REQUIRED)
endif()
if(${projectPrefix}BUILD_CXX_MODULES)
target_link_libraries(example_utils INTERFACE Microsoft.GSL::GSL)
endif()
target_link_libraries(example_utils-headers INTERFACE Microsoft.GSL::GSL)
target_compile_definitions(mp-units-core INTERFACE ${projectPrefix}API_CONTRACTS=3)
endif()
target_link_libraries(example_utils-headers INTERFACE mp-units-contracts)
#
# add_example(target <depependencies>...)

View File

@ -16,6 +16,7 @@
*/
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <iostream>
#ifdef MP_UNITS_MODULES
import mp_units;

View File

@ -16,6 +16,7 @@
*/
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <concepts>
#include <iostream>
#include <string>

View File

@ -36,14 +36,14 @@ import mp_units.core;
using namespace mp_units;
// clang-format off
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
QUANTITY_SPEC(currency, dim_currency);
inline constexpr struct euro : named_unit<"EUR", kind_of<currency>> {} euro;
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct great_british_pound : named_unit<"GBP", kind_of<currency>> {} great_british_pound;
inline constexpr struct japanese_jen : named_unit<"JPY", kind_of<currency>> {} japanese_jen;
inline constexpr struct euro final : named_unit<"EUR", kind_of<currency>> {} euro;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct great_british_pound final : named_unit<"GBP", kind_of<currency>> {} great_british_pound;
inline constexpr struct japanese_jen final : named_unit<"JPY", kind_of<currency>> {} japanese_jen;
// clang-format on
namespace unit_symbols {

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <iostream>
#include <string>
#include <string_view>

View File

@ -24,6 +24,7 @@
#include "glide_computer_lib.h"
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <array>
#include <chrono>
#include <concepts>

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "glide_computer_lib.h"
#include <mp-units/ext/format.h>
#include <functional>
#include <iostream>
#include <numeric>

View File

@ -26,6 +26,7 @@
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <iomanip>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -24,6 +24,7 @@
#include "ranged_representation.h"
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <compare>
#include <limits>
#include <numbers>
@ -39,7 +40,7 @@ import mp_units;
namespace geographic {
inline constexpr struct mean_sea_level : mp_units::absolute_point_origin<mean_sea_level, mp_units::isq::altitude> {
inline constexpr struct mean_sea_level final : mp_units::absolute_point_origin<mp_units::isq::altitude> {
} mean_sea_level;
using msl_altitude = mp_units::quantity_point<mp_units::isq::altitude[mp_units::si::metre], mean_sea_level>;
@ -67,10 +68,9 @@ struct MP_UNITS_STD_FMT::formatter<geographic::msl_altitude, Char> :
namespace geographic {
inline constexpr struct equator : mp_units::absolute_point_origin<equator, mp_units::isq::angular_measure> {
inline constexpr struct equator final : mp_units::absolute_point_origin<mp_units::isq::angular_measure> {
} equator;
inline constexpr struct prime_meridian :
mp_units::absolute_point_origin<prime_meridian, mp_units::isq::angular_measure> {
inline constexpr struct prime_meridian final : mp_units::absolute_point_origin<mp_units::isq::angular_measure> {
} prime_meridian;

View File

@ -25,6 +25,7 @@
#include "validated_type.h"
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <algorithm>
#include <concepts>
#include <type_traits>

View File

@ -24,6 +24,8 @@
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/contracts.h>
#include <mp-units/ext/format.h>
#include <compare> // IWYU pragma: export
#include <ostream>
#include <utility>

View File

@ -23,6 +23,7 @@
#pragma once
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <algorithm>
#include <locale>
#include <tuple>

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES
@ -63,7 +64,7 @@ int main()
const quantity process_noise_variance = 0.0001 * pow<2>(deg_C);
const estimate initial{state{qp{60. * deg_C}}, 100. * deg_C};
const std::array measurements = {qp{49.986 * deg_C}, qp{49.963 * deg_C}, qp{50.09 * deg_C}, qp{50.001 * deg_C},
const std::array measurements = {qp{49.986 * deg_C}, qp{49.963 * deg_C}, qp{50.097 * deg_C}, qp{50.001 * deg_C},
qp{50.018 * deg_C}, qp{50.05 * deg_C}, qp{49.938 * deg_C}, qp{49.858 * deg_C},
qp{49.965 * deg_C}, qp{50.114 * deg_C}};
const quantity measurement_error = 0.1 * deg_C;

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "kalman.h"
#include <mp-units/ext/format.h>
#include <array>
#include <iostream>
#ifdef MP_UNITS_MODULES

View File

@ -26,6 +26,7 @@
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <iostream>
#ifdef MP_UNITS_MODULES
import mp_units;

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <iostream>
#include <tuple>
#ifdef MP_UNITS_MODULES

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <cassert>
#include <chrono>
#include <iostream>

View File

@ -23,6 +23,7 @@
#include "geographic.h"
#include "ranged_representation.h"
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <cassert>
#include <cstdint>
#include <iostream>
@ -30,6 +31,7 @@
#ifdef MP_UNITS_MODULES
import mp_units;
#else
#include <mp-units/bits/fmt.h>
#include <mp-units/systems/international.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si.h>
@ -43,7 +45,7 @@ using namespace geographic;
enum class earth_gravity_model : std::int8_t { egm84_15, egm95_5, egm2008_1 };
template<earth_gravity_model M>
struct height_above_ellipsoid_t : absolute_point_origin<height_above_ellipsoid_t<M>, isq::altitude> {
struct height_above_ellipsoid_t final : absolute_point_origin<isq::altitude> {
static constexpr earth_gravity_model egm = M;
};
template<earth_gravity_model M>
@ -113,7 +115,7 @@ hae_altitude<M> to_hae(msl_altitude msl, position<long double> pos)
// **** HAL ****
// clang-format off
inline constexpr struct height_above_launch : absolute_point_origin<height_above_launch, isq::altitude> {} height_above_launch;
inline constexpr struct height_above_launch final : absolute_point_origin<isq::altitude> {} height_above_launch;
// clang-format on
using hal_altitude = quantity_point<isq::altitude[si::metre], height_above_launch>;

View File

@ -83,26 +83,29 @@ check_cxx_feature_supported(__cpp_lib_format ${projectPrefix}LIB_FORMAT_SUPPORTE
check_cxx_feature_supported("__cpp_constexpr >= 202211L" ${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)
check_cxx_feature_supported(__cpp_explicit_this_parameter ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
# libc++ has a basic supports for std::format but does not set __cpp_lib_format
# https://github.com/llvm/llvm-project/issues/77773
if(NOT ${projectPrefix}LIB_FORMAT_SUPPORTED
AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "17"
AND ${projectPrefix}LIBCXX
)
message(STATUS "Clang 17+ with libc++ detected, overriding `std::format` support")
set(${projectPrefix}LIB_FORMAT_SUPPORTED 1)
endif()
# validate settings
if(NOT ${projectPrefix}API_FREESTANDING
AND ${projectPrefix}API_STD_FORMAT STREQUAL "TRUE"
AND NOT
(${projectPrefix}LIB_FORMAT_SUPPORTED
# libc++ has a basic supports for std::format but does not set __cpp_lib_format
# https://github.com/llvm/llvm-project/issues/77773
OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "17"
AND ${projectPrefix}LIBCXX))
if(NOT ${projectPrefix}API_FREESTANDING AND "${projectPrefix}API_STD_FORMAT" AND NOT
${projectPrefix}LIB_FORMAT_SUPPORTED
)
message(FATAL_ERROR "`std::format` enabled but not supported")
endif()
if(${projectPrefix}API_STRING_VIEW_RET STREQUAL "TRUE" AND NOT
${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS
)
if("${projectPrefix}API_STRING_VIEW_RET" AND NOT ${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)
message(FATAL_ERROR "`std::string_view` returns enabled but not supported")
endif()
if(${projectPrefix}API_NO_CRTP STREQUAL "TRUE" AND NOT ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
if("${projectPrefix}API_NO_CRTP" AND NOT ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
message(FATAL_ERROR "`NO_CRTP` mode enabled but explicit `this` parameter is not supported")
endif()
@ -116,6 +119,7 @@ else()
endif()
# components/modules
include(MPUnitsContracts)
add_subdirectory(core)
add_subdirectory(systems)

View File

@ -0,0 +1,41 @@
# 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.
add_library(mp-units-contracts INTERFACE)
if(${projectPrefix}API_CONTRACTS STREQUAL "NONE")
target_compile_definitions(mp-units-contracts INTERFACE ${projectPrefix}API_CONTRACTS=0)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "GSL-LITE")
if(NOT TARGET gsl::gsl-lite)
find_package(gsl-lite REQUIRED)
endif()
target_link_libraries(mp-units-contracts INTERFACE gsl::gsl-lite)
target_compile_definitions(mp-units-contracts INTERFACE ${projectPrefix}API_CONTRACTS=2)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "MS-GSL")
if(NOT TARGET Microsoft.GSL::GSL)
find_package(Microsoft.GSL REQUIRED)
endif()
target_link_libraries(mp-units-contracts INTERFACE Microsoft.GSL::GSL)
target_compile_definitions(mp-units-contracts INTERFACE ${projectPrefix}API_CONTRACTS=3)
endif()
install(TARGETS mp-units-contracts EXPORT mp-unitsTargets)

View File

@ -23,8 +23,7 @@
cmake_minimum_required(VERSION 3.23)
function(set_feature_flag name)
set(val_list "TRUE" "FALSE")
if(${projectPrefix}${name} IN_LIST val_list)
if(NOT ${projectPrefix}${name} STREQUAL "AUTO")
target_compile_definitions(
mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}${name}=$<BOOL:${${projectPrefix}${name}}>
)
@ -36,15 +35,16 @@ add_mp_units_module(
core mp-units-core
HEADERS include/mp-units/bits/core_gmf.h
include/mp-units/bits/get_associated_quantity.h
include/mp-units/bits/get_common_base.h
include/mp-units/bits/hacks.h
include/mp-units/bits/math_concepts.h
include/mp-units/bits/module_macros.h
include/mp-units/bits/quantity_spec_hierarchy.h
include/mp-units/bits/ratio.h
include/mp-units/bits/sudo_cast.h
include/mp-units/bits/text_tools.h
include/mp-units/bits/type_list.h
include/mp-units/ext/algorithm.h
include/mp-units/ext/contracts.h
include/mp-units/ext/fixed_string.h
include/mp-units/ext/prime.h
include/mp-units/ext/type_name.h
@ -86,6 +86,7 @@ if(NOT ${projectPrefix}API_FREESTANDING)
FILES
include/mp-units/bits/fmt.h
include/mp-units/bits/requires_hosted.h
include/mp-units/ext/format.h
include/mp-units/math.h
include/mp-units/ostream.h
include/mp-units/format.h
@ -99,8 +100,8 @@ set_feature_flag(API_NO_CRTP)
# Text formatting
if(NOT ${projectPrefix}API_FREESTANDING
AND (${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED))
AND (NOT ${projectPrefix}API_STD_FORMAT OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED))
)
if(NOT TARGET fmt::fmt)
find_package(fmt REQUIRED)
@ -109,21 +110,7 @@ if(NOT ${projectPrefix}API_FREESTANDING
endif()
# Contracts checking
if(${projectPrefix}API_CONTRACTS STREQUAL "NONE")
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=0)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "GSL-LITE")
if(NOT TARGET gsl::gsl-lite)
find_package(gsl-lite REQUIRED)
endif()
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} gsl::gsl-lite)
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=2)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "MS-GSL")
if(NOT TARGET Microsoft.GSL::GSL)
find_package(Microsoft.GSL REQUIRED)
endif()
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} Microsoft.GSL::GSL)
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=3)
endif()
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} mp-units-contracts)
# C++20 modules
if(${projectPrefix}BUILD_CXX_MODULES)

View File

@ -24,6 +24,7 @@
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/contracts.h>
#include <array>
#include <compare>
#include <concepts>
@ -44,23 +45,13 @@
#include <utility>
#if MP_UNITS_HOSTED
#include <mp-units/ext/format.h>
#include <cmath>
#include <locale>
#include <ostream>
#include <random>
#include <sstream>
#include <string>
#if MP_UNITS_USE_FMTLIB
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
MP_UNITS_DIAGNOSTIC_IGNORE_SHADOW
#include <fmt/format.h>
MP_UNITS_DIAGNOSTIC_POP
#else
#include <format>
#endif
#endif
#if __cpp_lib_text_encoding

View File

@ -35,6 +35,8 @@
#include <mp-units/ext/algorithm.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <mp-units/ext/format.h>
#include <array>
#include <concepts>
#include <cstdint>

View File

@ -56,7 +56,7 @@ template<QuantitySpec A, QuantitySpec B>
}
template<QuantitySpec A, QuantitySpec B>
[[nodiscard]] consteval auto have_common_base(A a, B b)
[[nodiscard]] consteval bool have_common_base(A a, B b)
{
constexpr std::size_t a_length = hierarchy_path_length(A{});
constexpr std::size_t b_length = hierarchy_path_length(B{});
@ -68,7 +68,7 @@ template<QuantitySpec A, QuantitySpec B>
template<QuantitySpec A, QuantitySpec B>
requires(have_common_base_in_hierarchy_of_equal_length(A{}, B{}))
[[nodiscard]] consteval auto get_common_base_for_hierarchy_of_equal_length(A a, B b)
[[nodiscard]] consteval QuantitySpec auto get_common_base_for_hierarchy_of_equal_length(A a, B b)
{
if constexpr (is_same_v<A, B>)
return a;
@ -78,14 +78,29 @@ template<QuantitySpec A, QuantitySpec B>
template<QuantitySpec A, QuantitySpec B>
requires(have_common_base(A{}, B{}))
[[nodiscard]] consteval auto get_common_base(A a, B b)
[[nodiscard]] consteval QuantitySpec auto get_common_base(A a, B b)
{
constexpr int a_length = hierarchy_path_length(A{});
constexpr int b_length = hierarchy_path_length(B{});
constexpr std::size_t a_length = hierarchy_path_length(A{});
constexpr std::size_t b_length = hierarchy_path_length(B{});
if constexpr (a_length > b_length)
return get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b);
else
return get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b));
}
template<QuantitySpec Child, QuantitySpec Parent>
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p)
{
if constexpr (Child{} == Parent{})
return std::true_type{};
else {
constexpr std::size_t child_length = hierarchy_path_length(Child{});
constexpr std::size_t parent_length = hierarchy_path_length(Parent{});
if constexpr (parent_length > child_length)
return false;
else
return hierarchy_path_advance<child_length - parent_length>(ch) == p;
}
}
} // namespace mp_units::detail

View File

@ -27,6 +27,7 @@
#include <mp-units/compat_macros.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <compare> // IWYU pragma: export
#include <cstdint>
#include <numeric>

View File

@ -28,14 +28,14 @@
#ifdef MP_UNITS_API_NO_CRTP
#define QUANTITY_SPEC(name, ...) \
inline constexpr struct name : ::mp_units::quantity_spec<__VA_ARGS__> { \
#define QUANTITY_SPEC(name, ...) \
inline constexpr struct name final : ::mp_units::quantity_spec<__VA_ARGS__> { \
} name
#else
#define QUANTITY_SPEC(name, ...) \
inline constexpr struct name : ::mp_units::quantity_spec<name, __VA_ARGS__> { \
#define QUANTITY_SPEC(name, ...) \
inline constexpr struct name final : ::mp_units::quantity_spec<name, __VA_ARGS__> { \
} name
#endif
@ -83,26 +83,12 @@
#ifndef MP_UNITS_IN_MODULE_INTERFACE
// IWYU pragma: begin_exports
#if MP_UNITS_USE_FMTLIB
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
MP_UNITS_DIAGNOSTIC_IGNORE_SHADOW
#include <fmt/format.h>
MP_UNITS_DIAGNOSTIC_POP
#else
#include <format>
#endif
// IWYU pragma: end_exports
#endif
#endif // MP_UNITS_HOSTED
#if MP_UNITS_API_CONTRACTS == 2 || __has_include(<gsl/gsl-lite.hpp>)
#include <gsl/gsl-lite.hpp>
#define MP_UNITS_EXPECTS(expr) gsl_Expects(expr)
#define MP_UNITS_EXPECTS_DEBUG(expr) gsl_ExpectsDebug(expr)
#define MP_UNITS_ASSERT(expr) gsl_Assert(expr)
@ -110,9 +96,6 @@ MP_UNITS_DIAGNOSTIC_POP
#elif MP_UNITS_API_CONTRACTS == 3 || __has_include(<gsl/gsl>)
#include <gsl/gsl>
#include <cassert>
#define MP_UNITS_EXPECTS(expr) Expects(expr)
#if defined NDEBUG
#define MP_UNITS_EXPECTS_DEBUG(expr) static_cast<void>(0)

View File

@ -0,0 +1,49 @@
// 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
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#if MP_UNITS_API_CONTRACTS == 2 || __has_include(<gsl/gsl-lite.hpp>)
#if MP_UNITS_HOSTED
#include <gsl/gsl-lite.hpp>
#else
#include <mp-units/bits/requires_hosted.h>
#endif
#elif MP_UNITS_API_CONTRACTS == 3 || __has_include(<gsl/gsl>)
#if MP_UNITS_HOSTED
#include <gsl/gsl>
#include <cassert>
#else
#include <mp-units/bits/requires_hosted.h>
#endif
#endif
#endif // MP_UNITS_IN_MODULE_INTERFACE

View File

@ -32,12 +32,14 @@
#include <mp-units/ext/type_traits.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <compare> // IWYU pragma: export
#include <cstddef>
#include <cstdlib>
#include <ranges>
#include <string_view>
#if MP_UNITS_HOSTED
#include <mp-units/ext/format.h>
#include <ostream>
#endif
#endif

View File

@ -0,0 +1,42 @@
// 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
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#if MP_UNITS_USE_FMTLIB
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
MP_UNITS_DIAGNOSTIC_IGNORE_SHADOW
#include <fmt/format.h>
MP_UNITS_DIAGNOSTIC_POP
#else
#include <format>
#endif
#endif

View File

@ -34,6 +34,7 @@
#include <mp-units/framework/symbol_text.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <array>
#include <cstdint>
#include <iterator>
@ -61,9 +62,9 @@ namespace mp_units {
* For example:
*
* @code{.cpp}
* inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
* inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
* inline constexpr struct dim_mass : base_dimension<"M"> {} dim_mass;
* inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
* inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
* inline constexpr struct dim_mass final : base_dimension<"M"> {} dim_mass;
* @endcode
*
* @note A common convention in this library is to assign the same name for a type and an object of this type.
@ -86,6 +87,9 @@ struct base_dimension_less : std::bool_constant<(Lhs::symbol < Rhs::symbol)> {};
template<typename T1, typename T2>
using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
template<detail::DerivedDimensionExpr... Expr>
struct derived_dimension_impl : detail::expr_fractions<detail::is_dimension_one, Expr...> {};
} // namespace detail
/**
@ -131,7 +135,7 @@ using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
* instantiate this type automatically based on the dimensional arithmetic equation provided by the user.
*/
template<detail::DerivedDimensionExpr... Expr>
struct derived_dimension : detail::expr_fractions<detail::is_dimension_one, Expr...> {};
struct derived_dimension final : detail::derived_dimension_impl<Expr...> {};
/**
* @brief Dimension one
@ -140,7 +144,7 @@ struct derived_dimension : detail::expr_fractions<detail::is_dimension_one, Expr
* dimensions are zero. It is a dimension of a quantity of dimension one also known as
* "dimensionless".
*/
MP_UNITS_EXPORT inline constexpr struct dimension_one : derived_dimension<> {
MP_UNITS_EXPORT inline constexpr struct dimension_one final : detail::derived_dimension_impl<> {
} dimension_one;
namespace detail {
@ -279,13 +283,13 @@ constexpr Out dimension_symbol_impl(Out out, const type_list<Nums...>& nums, con
}
template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&, const dimension_symbol_formatting& fmt,
bool negative_power)
constexpr Out dimension_symbol_impl(Out out, const derived_dimension_impl<Expr...>&,
const dimension_symbol_formatting& fmt, bool negative_power)
{
(void)negative_power;
MP_UNITS_EXPECTS(negative_power == false);
return dimension_symbol_impl<CharT>(out, typename derived_dimension<Expr...>::_num_{},
typename derived_dimension<Expr...>::_den_{}, fmt);
return dimension_symbol_impl<CharT>(out, typename derived_dimension_impl<Expr...>::_num_{},
typename derived_dimension_impl<Expr...>::_den_{}, fmt);
}

View File

@ -42,20 +42,13 @@ template<typename T>
inline constexpr bool is_derived_from_specialization_of_base_dimension =
requires(T* t) { to_base_specialization_of_base_dimension(t); };
template<typename T>
inline constexpr bool is_specialization_of_base_dimension = false;
template<symbol_text Symbol>
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
/**
* @brief A concept matching all named base dimensions in the library.
*
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
*/
template<typename T>
concept BaseDimension =
is_derived_from_specialization_of_base_dimension<T> && (!is_specialization_of_base_dimension<T>);
concept BaseDimension = is_derived_from_specialization_of_base_dimension<T> && std::is_final_v<T>;
template<typename T>
struct is_dimension_one : std::false_type {};
@ -91,7 +84,8 @@ namespace detail {
* being the `dimension_one`.
*/
template<typename T>
concept DerivedDimension = is_specialization_of<T, derived_dimension> || is_dimension_one<T>::value;
concept DerivedDimension =
(is_specialization_of<T, derived_dimension> || is_dimension_one<T>::value) && std::is_final_v<T>;
} // namespace detail

View File

@ -29,6 +29,7 @@
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <cstdint>
#include <functional>
#endif
namespace mp_units {

View File

@ -517,8 +517,7 @@ template<typename T, auto... Ms>
constexpr T get_value(const magnitude<Ms...>&)
{
// Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow.
constexpr auto result = detail::checked_static_cast<T>((detail::compute_base_power<T>(Ms) * ... * T{1}));
constexpr T result = detail::checked_static_cast<T>((detail::compute_base_power<T>(Ms) * ... * T{1}));
return result;
}
@ -677,16 +676,6 @@ template<auto... Ms>
[[nodiscard]] consteval auto denominator(Magnitude auto m) { return numerator(pow<-1>(m)); }
// TODO This probably should not be exported but is used in chrono.h
MP_UNITS_EXPORT constexpr ratio as_ratio(Magnitude auto m)
requires(is_rational(decltype(m){}))
{
return ratio{
get_value<std::intmax_t>(numerator(m)),
get_value<std::intmax_t>(denominator(m)),
};
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Common Magnitude.
//
@ -758,7 +747,7 @@ template<auto H1, auto... T1, auto H2, auto... T2>
template<auto... Ms>
[[nodiscard]] consteval auto common_magnitude_type_impl(magnitude<Ms...>)
{
return (decltype(get_base_value(Ms)){} * ... * std::intmax_t{});
return (std::intmax_t{} * ... * decltype(get_base_value(Ms)){});
}
// Returns the most precise type to express the magnitude factor

View File

@ -37,6 +37,7 @@
#include <mp-units/framework/unit_concepts.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <compare> // IWYU pragma: export
#include <utility>
#endif
@ -45,16 +46,21 @@ namespace mp_units {
namespace detail {
template<auto UFrom, auto UTo>
concept IntegralConversionFactor = Unit<decltype(UFrom)> && Unit<decltype(UTo)> &&
is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag);
template<Unit UFrom, Unit UTo>
[[nodiscard]] consteval bool integral_conversion_factor(UFrom from, UTo to)
{
if constexpr (is_same_v<UFrom, UTo>)
return true;
else
return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag);
}
template<typename QFrom, typename QTo>
concept QuantityConvertibleTo =
Quantity<QFrom> && Quantity<QTo> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
convertible(QFrom::unit, QTo::unit) &&
(treat_as_floating_point<typename QTo::rep> ||
(!treat_as_floating_point<typename QFrom::rep> && IntegralConversionFactor<QFrom::unit, QTo::unit>)) &&
(!treat_as_floating_point<typename QFrom::rep> && (integral_conversion_factor(QFrom::unit, QTo::unit)))) &&
// TODO consider providing constraints of sudo_cast here rather than testing if it can be called (its return type is
// deduced thus the function is evaluated here and may emit truncating conversion or other warnings)
requires(QFrom q) { detail::sudo_cast<QTo>(q); };

View File

@ -35,11 +35,10 @@
namespace mp_units {
MP_UNITS_EXPORT template<typename Derived, QuantitySpec auto QS>
MP_UNITS_EXPORT template<QuantitySpec auto QS>
// NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
struct absolute_point_origin {
static constexpr QuantitySpec auto quantity_spec = QS;
using _type_ = absolute_point_origin;
};
MP_UNITS_EXPORT template<QuantityPoint auto QP>
@ -56,7 +55,7 @@ struct relative_point_origin {
};
template<QuantitySpec auto QS>
struct zeroth_point_origin_ : absolute_point_origin<zeroth_point_origin_<QS>, QS> {};
struct zeroth_point_origin_ final : absolute_point_origin<QS> {};
MP_UNITS_EXPORT template<QuantitySpec auto QS>
inline constexpr zeroth_point_origin_<QS> zeroth_point_origin;
@ -81,9 +80,8 @@ MP_UNITS_EXPORT template<PointOrigin PO1, PointOrigin PO2>
[[nodiscard]] consteval bool operator==(PO1 po1, PO2 po2)
{
if constexpr (detail::AbsolutePointOrigin<PO1> && detail::AbsolutePointOrigin<PO2>)
return is_same_v<typename PO1::_type_, typename PO2::_type_> ||
(detail::is_zeroth_point_origin(po1) && detail::is_zeroth_point_origin(po2) &&
interconvertible(po1.quantity_spec, po2.quantity_spec));
return is_same_v<PO1, PO2> || (detail::is_zeroth_point_origin(po1) && detail::is_zeroth_point_origin(po2) &&
interconvertible(po1.quantity_spec, po2.quantity_spec));
else if constexpr (detail::RelativePointOrigin<PO1> && detail::RelativePointOrigin<PO2>)
return PO1::quantity_point == PO2::quantity_point;
else if constexpr (detail::RelativePointOrigin<PO1>)

View File

@ -32,7 +32,7 @@
namespace mp_units {
MP_UNITS_EXPORT template<typename Derived, QuantitySpec auto QS>
MP_UNITS_EXPORT template<QuantitySpec auto QS>
struct absolute_point_origin;
namespace detail {
@ -40,22 +40,15 @@ namespace detail {
template<typename T>
inline constexpr bool is_quantity_point = false;
template<typename T>
inline constexpr bool is_specialization_of_absolute_point_origin = false;
template<typename D, auto Q>
inline constexpr bool is_specialization_of_absolute_point_origin<absolute_point_origin<D, Q>> = true;
template<typename D, auto Q>
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<D, Q>*);
template<auto Q>
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<Q>*);
template<typename T>
inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
requires(T* t) { to_base_specialization_of_absolute_point_origin(t); };
template<typename T>
concept AbsolutePointOrigin =
is_derived_from_specialization_of_absolute_point_origin<T> && !is_specialization_of_absolute_point_origin<T>;
concept AbsolutePointOrigin = is_derived_from_specialization_of_absolute_point_origin<T> && std::is_final_v<T>;
} // namespace detail
@ -72,12 +65,6 @@ struct relative_point_origin;
namespace detail {
template<typename T>
inline constexpr bool is_specialization_of_relative_point_origin = false;
template<auto QP>
inline constexpr bool is_specialization_of_relative_point_origin<relative_point_origin<QP>> = true;
template<auto QP>
void to_base_specialization_of_relative_point_origin(const volatile relative_point_origin<QP>*);
@ -86,8 +73,7 @@ inline constexpr bool is_derived_from_specialization_of_relative_point_origin =
requires(T* t) { to_base_specialization_of_relative_point_origin(t); };
template<typename T>
concept RelativePointOrigin =
is_derived_from_specialization_of_relative_point_origin<T> && !is_specialization_of_relative_point_origin<T>;
concept RelativePointOrigin = is_derived_from_specialization_of_relative_point_origin<T> && std::is_final_v<T>;
} // namespace detail

View File

@ -23,9 +23,9 @@
#pragma once
// IWYU pragma: private, include <mp-units/framework.h>
#include <mp-units/bits/get_common_base.h>
#include <mp-units/bits/hacks.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/quantity_spec_hierarchy.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/algorithm.h>
#include <mp-units/ext/type_name.h>
@ -199,13 +199,13 @@ MP_UNITS_EXPORT_END
* For example:
*
* @code{.cpp}
* inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
* inline constexpr struct dim_mass : base_dimension<"M"> {} dim_mass;
* inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
* inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
* inline constexpr struct dim_mass final : base_dimension<"M"> {} dim_mass;
* inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
*
* inline constexpr struct length : quantity_spec<dim_length> {} length;
* inline constexpr struct mass : quantity_spec<dim_mass> {} mass;
* inline constexpr struct time : quantity_spec<dim_time> {} time;
* inline constexpr struct length final : quantity_spec<dim_length> {} length;
* inline constexpr struct mass final : quantity_spec<dim_mass> {} mass;
* inline constexpr struct time final : quantity_spec<dim_time> {} time;
* @endcode
*
* @note A common convention in this library is to assign the same name for a type and an object of this type.
@ -225,6 +225,7 @@ template<typename Self, detail::BaseDimension auto Dim, one_of<quantity_characte
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self> {
#endif
using _base_type_ = quantity_spec;
static constexpr detail::BaseDimension auto dimension = Dim;
static constexpr quantity_character character = detail::quantity_character_init<Args...>(quantity_character::scalar);
};
@ -243,12 +244,12 @@ struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self>
* For example:
*
* @code{.cpp}
* inline constexpr struct area : quantity_spec<pow<2>(length)> {} area;
* inline constexpr struct volume : quantity_spec<pow<3>(length)> {} volume;
* inline constexpr struct velocity : quantity_spec<position_vector / duration> {} velocity;
* inline constexpr struct speed : quantity_spec<length / time> {} speed;
* inline constexpr struct force : quantity_spec<mass * acceleration, quantity_character::vector> {} force;
* inline constexpr struct power : quantity_spec<force * velocity, quantity_character::scalar> {} power;
* inline constexpr struct area final : quantity_spec<pow<2>(length)> {} area;
* inline constexpr struct volume final : quantity_spec<pow<3>(length)> {} volume;
* inline constexpr struct velocity final : quantity_spec<position_vector / duration> {} velocity;
* inline constexpr struct speed final : quantity_spec<length / time> {} speed;
* inline constexpr struct force final : quantity_spec<mass * acceleration, quantity_character::vector> {} force;
* inline constexpr struct power final : quantity_spec<force * velocity, quantity_character::scalar> {} power;
* @endcode
*
* @note A common convention in this library is to assign the same name for a type and an object of this type.
@ -260,19 +261,32 @@ struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self>
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
*/
#ifdef MP_UNITS_API_NO_CRTP
template<detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
template<detail::DerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Eq, Args...> : detail::quantity_spec_interface {
#else
template<typename Self, detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
template<typename Self, detail::DerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self> {
#endif
using _base_type_ = quantity_spec;
static constexpr auto _equation_ = Eq;
static constexpr Dimension auto dimension = Eq.dimension;
static constexpr quantity_character character = detail::quantity_character_init<Args...>(Eq.character);
};
namespace detail {
template<QuantitySpec auto Q, bool = requires { Q._equation_; }>
struct propagate_equation {};
template<QuantitySpec auto Q>
struct propagate_equation<Q, true> {
static constexpr auto _equation_ = Q._equation_;
};
} // namespace detail
/**
* @brief Specialization defining a leaf quantity in the hierarchy
*
@ -285,10 +299,10 @@ struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self>
* For example:
*
* @code{.cpp}
* inline constexpr struct width : quantity_spec<length> {} width;
* inline constexpr struct height : quantity_spec<length> {} height;
* inline constexpr struct diameter : quantity_spec<width> {} diameter;
* inline constexpr struct position_vector : quantity_spec<length, quantity_character::vector> {} position_vector;
* inline constexpr struct width final : quantity_spec<length> {} width;
* inline constexpr struct height final : quantity_spec<length> {} height;
* inline constexpr struct diameter final : quantity_spec<width> {} diameter;
* inline constexpr struct position_vector final : quantity_spec<length, quantity_character::vector> {} position_vector;
* @endcode
*
* @note A common convention in this library is to assign the same name for a type and an object of this type.
@ -303,13 +317,15 @@ struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self>
#ifdef MP_UNITS_API_NO_CRTP
template<detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<QS, Args...> : decltype(QS) {
struct quantity_spec<QS, Args...> : detail::propagate_equation<QS>, detail::quantity_spec_interface {
#else
template<typename Self, detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, QS, Args...> : decltype(QS) {
struct quantity_spec<Self, QS, Args...> : detail::propagate_equation<QS>, detail::quantity_spec_interface<Self> {
#endif
using _base_type_ = quantity_spec;
static constexpr auto _parent_ = QS;
static constexpr Dimension auto dimension = _parent_.dimension;
static constexpr quantity_character character = detail::quantity_character_init<Args...>(QS.character);
#ifndef MP_UNITS_API_NO_CRTP
@ -330,6 +346,7 @@ struct quantity_spec<Self, QS, Args...> : decltype(QS) {
#endif
};
// clang-format off
/**
* @brief Specialization defining a leaf derived quantity in the hierarchy and refining paren't equation
*
@ -343,10 +360,10 @@ struct quantity_spec<Self, QS, Args...> : decltype(QS) {
* For example:
*
* @code{.cpp}
* inline constexpr struct angular_measure : quantity_spec<dimensionless, arc_length / radius, is_kind> {}
* angular_measure; inline constexpr struct velocity : quantity_spec<speed, position_vector / duration> {} velocity;
* inline constexpr struct weight : quantity_spec<force, mass * acceleration_of_free_fall> {} weight;
* inline constexpr struct kinetic_energy : quantity_spec<mechanical_energy, mass * pow<2>(speed)> {} kinetic_energy;
* inline constexpr struct angular_measure final : quantity_spec<dimensionless, arc_length / radius, is_kind> {} angular_measure;
* inline constexpr struct velocity final : quantity_spec<speed, position_vector / duration> {} velocity;
* inline constexpr struct weight final : quantity_spec<force, mass * acceleration_of_free_fall> {} weight;
* inline constexpr struct kinetic_energy final : quantity_spec<mechanical_energy, mass * pow<2>(speed)> {} kinetic_energy;
* @endcode
*
* @note A common convention in this library is to assign the same name for a type and an object of this type.
@ -358,25 +375,50 @@ struct quantity_spec<Self, QS, Args...> : decltype(QS) {
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
* or `is_kind` in case the quantity starts a new hierarchy tree of a kind
*/
// clang-format on
#ifdef MP_UNITS_API_NO_CRTP
template<detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
template<detail::NamedQuantitySpec auto QS, detail::DerivedQuantitySpec auto Eq,
one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } || (requires {
QS._equation_;
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<QS, Eq, Args...> : quantity_spec<QS, Args...> {
struct quantity_spec<QS, Eq, Args...> : detail::quantity_spec_interface {
#else
template<typename Self, detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
template<typename Self, detail::NamedQuantitySpec auto QS, detail::DerivedQuantitySpec auto Eq,
one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } || (requires {
QS._equation_;
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
struct quantity_spec<Self, QS, Eq, Args...> : detail::quantity_spec_interface<Self> {
#endif
using _base_type_ = quantity_spec;
static constexpr auto _parent_ = QS;
static constexpr auto _equation_ = Eq;
static constexpr Dimension auto dimension = _parent_.dimension;
static constexpr quantity_character character = detail::quantity_character_init<Args...>(Eq.character);
};
namespace detail {
template<detail::DerivedQuantitySpecExpr... Expr>
struct derived_quantity_spec_impl :
#ifdef MP_UNITS_API_NO_CRTP
detail::quantity_spec_interface,
#else
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
#endif
detail::expr_fractions<detail::is_dimensionless, Expr...> {
using _base_type_ = derived_quantity_spec_impl;
using _base_ = detail::expr_fractions<detail::is_dimensionless, Expr...>;
static constexpr Dimension auto dimension =
detail::expr_map<detail::to_dimension, derived_dimension, struct dimension_one,
detail::type_list_of_base_dimension_less>(_base_{});
static constexpr quantity_character character =
detail::derived_quantity_character(typename _base_::_num_{}, typename _base_::_den_{});
};
} // namespace detail
/**
* @brief A specification of a derived quantity
@ -421,22 +463,8 @@ struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
* instantiate this type automatically based on the dimensional arithmetic equation provided by the user.
*/
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
struct derived_quantity_spec :
#ifdef MP_UNITS_API_NO_CRTP
detail::quantity_spec_interface,
#else
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
#endif
detail::expr_fractions<detail::is_dimensionless, Expr...> {
using _base_ = detail::expr_fractions<detail::is_dimensionless, Expr...>;
static constexpr Dimension auto dimension =
detail::expr_map<detail::to_dimension, derived_dimension, struct dimension_one,
detail::type_list_of_base_dimension_less>(_base_{});
static constexpr quantity_character character =
detail::derived_quantity_character(typename _base_::_num_{}, typename _base_::_den_{});
};
template<detail::DerivedQuantitySpecExpr... Expr>
struct derived_quantity_spec final : detail::derived_quantity_spec_impl<Expr...> {};
/**
* @brief Quantity of dimension one
@ -446,6 +474,13 @@ struct derived_quantity_spec :
*/
MP_UNITS_EXPORT QUANTITY_SPEC(dimensionless, derived_quantity_spec<>{});
namespace detail {
template<>
struct is_dimensionless<struct dimensionless> : std::true_type {};
} // namespace detail
/**
* @brief Quantity kind specifier
*
@ -454,7 +489,7 @@ MP_UNITS_EXPORT QUANTITY_SPEC(dimensionless, derived_quantity_spec<>{});
namespace detail {
template<typename T>
concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>;
concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::DerivedQuantitySpec<T>;
template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q);
@ -464,7 +499,8 @@ template<QuantitySpec Q>
#ifdef MP_UNITS_API_NO_CRTP
template<typename Q>
requires detail::QuantitySpecWithNoSpecifiers<Q> && (detail::get_kind_tree_root(Q{}) == Q{})
struct kind_of_<Q> : Q {
struct kind_of_<Q> final : Q::_base_type_ {
using _base_type_ = kind_of_;
static constexpr auto _quantity_spec_ = Q{};
};
#else
@ -476,7 +512,8 @@ template<typename Q>
template<detail::QuantitySpecWithNoSpecifiers Q>
requires(detail::get_kind_tree_root(Q{}) == Q{})
#endif
struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q{}> {
struct kind_of_<Q> final : quantity_spec<kind_of_<Q>, Q{}>::_base_type_ {
using _base_type_ = kind_of_;
static constexpr auto _quantity_spec_ = Q{};
};
#endif
@ -487,9 +524,6 @@ inline constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
namespace detail {
template<>
struct is_dimensionless<struct dimensionless> : std::true_type {};
template<QuantitySpec auto... From, QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto clone_kind_of(Q q)
{
@ -556,7 +590,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
return dimensionless;
else if constexpr (detail::ratio{Num, Den} == 1)
return q;
else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>)
else if constexpr (detail::DerivedQuantitySpec<Q>)
return detail::clone_kind_of<Q{}>(
detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
detail::remove_kind(q)));
@ -590,8 +624,6 @@ MP_UNITS_EXPORT_END
namespace detail {
enum class specs_convertible_result : std::int8_t { no, cast, explicit_conversion, yes };
template<QuantitySpec Q>
[[nodiscard]] consteval int get_complexity(Q);
@ -616,7 +648,7 @@ template<typename Q>
template<QuantitySpec Q>
[[nodiscard]] consteval int get_complexity(Q)
{
if constexpr (detail::IntermediateDerivedQuantitySpec<Q>)
if constexpr (detail::DerivedQuantitySpec<Q>)
return get_complexity(typename Q::_num_{}) + get_complexity(typename Q::_den_{});
else if constexpr (requires { Q::_equation_; })
return 1 + get_complexity(Q::_equation_);
@ -659,6 +691,8 @@ template<QuantitySpec Q>
return true;
}
enum class specs_convertible_result : std::int8_t { no, cast, explicit_conversion, yes };
template<QuantitySpec Q>
struct explode_to_equation_result {
Q equation;
@ -709,7 +743,7 @@ explode_result(Q) -> explode_result<Q>;
#endif
template<int Complexity, IntermediateDerivedQuantitySpec Q>
template<int Complexity, DerivedQuantitySpec Q>
[[nodiscard]] consteval auto explode(Q q);
template<int Complexity, NamedQuantitySpec Q>
@ -771,7 +805,7 @@ template<int Complexity, QuantitySpec Q>
return explode_result{dimensionless};
}
template<int Complexity, IntermediateDerivedQuantitySpec Q>
template<int Complexity, DerivedQuantitySpec Q>
[[nodiscard]] consteval auto explode(Q q)
{
constexpr auto c = get_complexity(Q{});
@ -1304,7 +1338,7 @@ template<typename... DensTo>
return specs_convertible_result::yes;
}
template<IntermediateDerivedQuantitySpec From, IntermediateDerivedQuantitySpec To>
template<DerivedQuantitySpec From, DerivedQuantitySpec To>
[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To)
{
return are_ingredients_convertible(type_list_sort<typename From::_num_, type_list_of_ingredients_less>{},
@ -1313,7 +1347,7 @@ template<IntermediateDerivedQuantitySpec From, IntermediateDerivedQuantitySpec T
type_list_sort<typename To::_den_, type_list_of_ingredients_less>{});
}
template<IntermediateDerivedQuantitySpec From, NamedQuantitySpec To>
template<DerivedQuantitySpec From, NamedQuantitySpec To>
[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To)
{
return are_ingredients_convertible(type_list_sort<typename From::_num_, type_list_of_ingredients_less>{},
@ -1321,7 +1355,7 @@ template<IntermediateDerivedQuantitySpec From, NamedQuantitySpec To>
type_list<To>{}, type_list<>{});
}
template<NamedQuantitySpec From, IntermediateDerivedQuantitySpec To>
template<NamedQuantitySpec From, DerivedQuantitySpec To>
[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To)
{
return are_ingredients_convertible(type_list<From>{}, type_list<>{},
@ -1353,8 +1387,8 @@ template<NamedQuantitySpec From, NamedQuantitySpec To>
using enum specs_convertible_result;
if constexpr (have_common_base(From{}, To{})) {
if constexpr (std::derived_from<From, To>) return yes;
if constexpr (std::derived_from<To, From>) return explicit_conversion;
if constexpr (is_child_of(From{}, To{})) return yes;
if constexpr (is_child_of(To{}, From{})) return explicit_conversion;
if constexpr (get_kind(From{}) == get_kind(To{})) return cast;
return no;
} else if constexpr (get_kind(From{}) != get_kind(To{}))
@ -1385,9 +1419,9 @@ template<QuantitySpec From, QuantitySpec To>
return yes;
else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
return convertible_named(from, to);
} else if constexpr (IntermediateDerivedQuantitySpec<From> && IntermediateDerivedQuantitySpec<To>) {
} else if constexpr (DerivedQuantitySpec<From> && DerivedQuantitySpec<To>) {
return are_ingredients_convertible(from, to);
} else if constexpr (IntermediateDerivedQuantitySpec<From>) {
} else if constexpr (DerivedQuantitySpec<From>) {
auto res = explode<get_complexity(to)>(from);
if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
return convertible_impl(res.quantity, to);
@ -1396,7 +1430,7 @@ template<QuantitySpec From, QuantitySpec To>
return min(eq.result, convertible_impl(res.quantity, eq.equation));
} else
return are_ingredients_convertible(from, to);
} else if constexpr (IntermediateDerivedQuantitySpec<To>) {
} else if constexpr (DerivedQuantitySpec<To>) {
auto res = explode<get_complexity(from)>(to);
if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
return min(res.result, convertible_impl(from, res.quantity));
@ -1473,7 +1507,7 @@ template<QuantitySpec Q>
return q;
} else if constexpr (requires { Q::_parent_; }) {
return get_kind_tree_root(Q::_parent_);
} else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) {
} else if constexpr (detail::DerivedQuantitySpec<Q>) {
return detail::expr_map<detail::to_kind, derived_quantity_spec, struct dimensionless,
detail::type_list_of_quantity_spec_less>(q);
} else {
@ -1511,11 +1545,11 @@ template<QuantitySpec Q1, QuantitySpec Q2>
else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>)
return detail::remove_kind(q2);
else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) ||
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
(detail::DerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
implicitly_convertible(Q1{}, Q2{})))
return q2;
else if constexpr ((!detail::QuantityKindSpec<Q1> && detail::QuantityKindSpec<Q2>) ||
(detail::NamedQuantitySpec<QQ1> && detail::IntermediateDerivedQuantitySpec<QQ2> &&
(detail::NamedQuantitySpec<QQ1> && detail::DerivedQuantitySpec<QQ2> &&
implicitly_convertible(Q2{}, Q1{})))
return q1;
else if constexpr (detail::have_common_base(Q1{}, Q2{}))

View File

@ -64,25 +64,14 @@ template<typename T>
inline constexpr bool is_derived_from_specialization_of_quantity_spec =
requires(T* t) { to_base_specialization_of_quantity_spec(t); };
template<typename T>
inline constexpr bool is_specialization_of_quantity_spec = false;
#ifdef MP_UNITS_API_NO_CRTP
template<auto... Args>
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<Args...>> = true;
#else
template<typename T, auto... Args>
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<T, Args...>> = true;
#endif
/**
* @brief Concept matching all named quantity specification types
*
* Satisfied by all types that derive from `quantity_spec`.
*/
template<typename T>
concept NamedQuantitySpec = is_derived_from_specialization_of_quantity_spec<T> &&
(!is_specialization_of_quantity_spec<T>)&&(!QuantityKindSpec<T>);
concept NamedQuantitySpec =
is_derived_from_specialization_of_quantity_spec<T> && std::is_final_v<T> && (!QuantityKindSpec<T>);
template<typename T>
struct is_dimensionless : std::false_type {};
@ -101,13 +90,12 @@ inline constexpr bool is_per_of_quantity_specs<per<Ts...>> =
(... && (NamedQuantitySpec<Ts> || is_dimensionless<Ts>::value || is_power_of_quantity_spec<Ts>));
template<typename T>
concept IntermediateDerivedQuantitySpecExpr =
detail::NamedQuantitySpec<T> || detail::is_dimensionless<T>::value || detail::is_power_of_quantity_spec<T> ||
detail::is_per_of_quantity_specs<T>;
concept DerivedQuantitySpecExpr = detail::NamedQuantitySpec<T> || detail::is_dimensionless<T>::value ||
detail::is_power_of_quantity_spec<T> || detail::is_per_of_quantity_specs<T>;
} // namespace detail
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
template<detail::DerivedQuantitySpecExpr... Expr>
struct derived_quantity_spec;
namespace detail {
@ -121,7 +109,7 @@ namespace detail {
* explicitly not supported here.
*/
template<typename T>
concept IntermediateDerivedQuantitySpec =
concept DerivedQuantitySpec =
is_specialization_of<T, derived_quantity_spec> ||
(QuantityKindSpec<T> &&
is_specialization_of<std::remove_const_t<decltype(T::_quantity_spec_)>, derived_quantity_spec>);
@ -130,20 +118,21 @@ concept IntermediateDerivedQuantitySpec =
MP_UNITS_EXPORT template<typename T>
concept QuantitySpec =
detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T> || detail::QuantityKindSpec<T>;
concept QuantitySpec = detail::NamedQuantitySpec<T> || detail::DerivedQuantitySpec<T> || detail::QuantityKindSpec<T>;
MP_UNITS_EXPORT template<QuantitySpec Q>
[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q);
namespace detail {
template<auto To, auto From>
concept NestedQuantityKindSpecOf =
QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> && get_kind(From) != get_kind(To) &&
std::derived_from<decltype(To), std::remove_const_t<decltype(get_kind(From)._quantity_spec_)>>;
template<QuantitySpec Child, QuantitySpec Parent>
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p);
}
template<auto To, auto From>
concept NestedQuantityKindSpecOf = QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> &&
get_kind(From) != get_kind(To) && is_child_of(To, get_kind(From)._quantity_spec_);
} // namespace detail
MP_UNITS_EXPORT template<typename T, auto QS>
concept QuantitySpecOf =

View File

@ -31,6 +31,7 @@
#include <mp-units/ext/fixed_string.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <compare> // IWYU pragma: export
#include <cstddef>
#include <cstdint>

View File

@ -45,10 +45,10 @@ namespace mp_units {
* @code{.cpp}
* // hypothetical natural system of units for c=1
*
* inline constexpr struct second : named_unit<"s"> {} second;
* inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
* inline constexpr struct gram : named_unit<"g"> {} gram;
* inline constexpr struct kilogram : decltype(si::kilo<gram>) {} kilogram;
* inline constexpr struct second final : named_unit<"s"> {} second;
* inline constexpr struct minute final : named_unit<"min", mag<60> * second> {} minute;
* inline constexpr struct gram final : named_unit<"g"> {} gram;
* inline constexpr auto kilogram = si::kilo<gram>;
*
* inline constexpr struct time : system_reference<isq::time, second> {} time;
* inline constexpr struct length : system_reference<isq::length, second> {} length;

View File

@ -41,6 +41,7 @@
#include <mp-units/framework/unit_concepts.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <mp-units/ext/contracts.h>
#include <array>
#include <cstdint>
#include <iterator>
@ -62,6 +63,13 @@ struct propagate_point_origin<U, true> {
static constexpr auto point_origin = U::point_origin;
};
template<Magnitude auto M, Unit U>
struct scaled_unit_impl : detail::propagate_point_origin<U> {
using _base_type_ = scaled_unit_impl; // exposition only
static constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(Magnitude) auto mag = M;
static constexpr U reference_unit{};
};
} // namespace detail
/**
@ -74,10 +82,7 @@ struct propagate_point_origin<U, true> {
* instantiate this type automatically based on the unit arithmetic equation provided by the user.
*/
template<Magnitude auto M, Unit U>
struct scaled_unit : detail::propagate_point_origin<U> {
static constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(Magnitude) auto mag = M;
static constexpr U reference_unit{};
};
struct scaled_unit final : detail::scaled_unit_impl<M, U> {};
namespace detail {
@ -100,12 +105,12 @@ inline constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true
* For example:
*
* @code{.cpp}
* inline constexpr struct second : named_unit<"s", time> {} second;
* inline constexpr struct metre : named_unit<"m", length> {} metre;
* inline constexpr struct hertz : named_unit<"Hz", inverse(second)> {} hertz;
* inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
* inline constexpr struct degree_Celsius : named_unit<{u8"°C", "`C"}, kelvin> {} degree_Celsius;
* inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
* inline constexpr struct second final : named_unit<"s", kind_of<time>> {} second;
* inline constexpr struct metre final : named_unit<"m", kind_of<length> {} metre;
* inline constexpr struct hertz final : named_unit<"Hz", inverse(second), kind_of<frequency>> {} hertz;
* inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
* inline constexpr struct degree_Celsius final : named_unit<{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {}
* degree_Celsius; inline constexpr struct minute final : named_unit<"min", mag<60> * second> {} minute;
* @endcode
*
* @note A common convention in this library is to assign the same name for a type and an object of this type.
@ -137,6 +142,7 @@ struct named_unit;
template<symbol_text Symbol, detail::QuantityKindSpec auto QS>
requires(!Symbol.empty()) && detail::BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
struct named_unit<Symbol, QS> {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
static constexpr auto quantity_spec = QS;
};
@ -144,6 +150,7 @@ struct named_unit<Symbol, QS> {
template<symbol_text Symbol, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
requires(!Symbol.empty()) && detail::BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
struct named_unit<Symbol, QS, PO> {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
static constexpr auto quantity_spec = QS;
static constexpr auto point_origin = PO;
@ -162,6 +169,7 @@ struct named_unit<Symbol, QS, PO> {
template<symbol_text Symbol>
requires(!Symbol.empty())
struct named_unit<Symbol> {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
};
@ -175,13 +183,15 @@ struct named_unit<Symbol> {
*/
template<symbol_text Symbol, Unit auto U>
requires(!Symbol.empty())
struct named_unit<Symbol, U> : decltype(U) {
struct named_unit<Symbol, U> : decltype(U)::_base_type_ {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique unit identifier
};
template<symbol_text Symbol, Unit auto U, PointOrigin auto PO>
requires(!Symbol.empty())
struct named_unit<Symbol, U, PO> : decltype(U) {
struct named_unit<Symbol, U, PO> : decltype(U)::_base_type_ {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique unit identifier
static constexpr auto point_origin = PO;
};
@ -197,14 +207,16 @@ struct named_unit<Symbol, U, PO> : decltype(U) {
*/
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS>
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
struct named_unit<Symbol, U, QS> : decltype(U) {
struct named_unit<Symbol, U, QS> : decltype(U)::_base_type_ {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique unit identifier
static constexpr auto quantity_spec = QS;
};
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
struct named_unit<Symbol, U, QS, PO> : decltype(U) {
struct named_unit<Symbol, U, QS, PO> : decltype(U)::_base_type_ {
using _base_type_ = named_unit; // exposition only
static constexpr auto symbol = Symbol; ///< Unique unit identifier
static constexpr auto quantity_spec = QS;
static constexpr auto point_origin = PO;
@ -225,7 +237,7 @@ struct named_unit<Symbol, U, QS, PO> : decltype(U) {
* template<PrefixableUnit auto U>
* inline constexpr kilo_<U> kilo;
*
* inline constexpr struct kilogram : decltype(si::kilo<gram>) {} kilogram;
* inline constexpr auto kilogram = si::kilo<gram>;
* @endcode
*
* @tparam Symbol a prefix text to prepend to a unit symbol
@ -234,7 +246,8 @@ struct named_unit<Symbol, U, QS, PO> : decltype(U) {
*/
MP_UNITS_EXPORT template<symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
requires(!Symbol.empty())
struct prefixed_unit : decltype(M * U) {
struct prefixed_unit : decltype(M * U)::_base_type_ {
using _base_type_ = prefixed_unit; // exposition only
static constexpr auto symbol = Symbol + U.symbol;
};
@ -243,6 +256,11 @@ namespace detail {
template<typename T>
struct is_one : std::false_type {};
template<DerivedUnitExpr... Expr>
struct derived_unit_impl : detail::expr_fractions<detail::is_one, Expr...> {
using _base_type_ = derived_unit_impl; // exposition only
};
} // namespace detail
/**
@ -291,7 +309,7 @@ struct is_one : std::false_type {};
* instantiate this type automatically based on the unit arithmetic equation provided by the user.
*/
template<detail::DerivedUnitExpr... Expr>
struct derived_unit : detail::expr_fractions<detail::is_one, Expr...> {};
struct derived_unit final : detail::derived_unit_impl<Expr...> {};
/**
* @brief Unit one
@ -299,7 +317,7 @@ struct derived_unit : detail::expr_fractions<detail::is_one, Expr...> {};
* Unit of a dimensionless quantity.
*/
// clang-format off
MP_UNITS_EXPORT inline constexpr struct one : derived_unit<> {} one;
MP_UNITS_EXPORT inline constexpr struct one final : detail::derived_unit_impl<> {} one;
// clang-format on
namespace detail {
@ -334,9 +352,6 @@ canonical_unit(M, U) -> canonical_unit<M, U>;
#endif
template<Unit T, symbol_text Symbol, detail::QuantityKindSpec auto Q, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q, Args...>&);
template<Unit T, symbol_text Symbol, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&);
@ -347,21 +362,15 @@ template<typename T, typename F, int Num, int... Den>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&);
template<Unit T, typename... Expr>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Expr...>&);
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit_impl<Expr...>&);
template<Unit T, auto M, typename U>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit<M, U>&)
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit_impl<M, U>&)
{
auto base = get_canonical_unit_impl(U{}, U{});
return canonical_unit{M * base.mag, base.reference_unit};
}
template<Unit T, symbol_text Symbol, detail::QuantityKindSpec auto Q, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q, Args...>&)
{
return canonical_unit{mag<1>, t};
}
template<Unit T, symbol_text Symbol, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&)
{
@ -405,7 +414,7 @@ template<typename... Us>
}
template<Unit T, typename... Expr>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Expr...>&)
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit_impl<Expr...>&)
{
auto num = get_canonical_unit_impl(typename derived_unit<Expr...>::_num_{});
auto den = get_canonical_unit_impl(typename derived_unit<Expr...>::_den_{});
@ -493,43 +502,13 @@ MP_UNITS_EXPORT_END
namespace detail {
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(...) { return false; }
template<symbol_text Symbol, auto... D>
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const named_unit<Symbol, D...>&,
const named_unit<Symbol, D...>&)
template<Unit U1, Unit U2>
[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2)
{
return true;
}
template<typename F1, typename F2, auto... Vs>
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const power<F1, Vs...>&, const power<F2, Vs...>&)
{
return have_same_canonical_reference_unit_impl(F1{}, F2{});
}
template<typename... Us1, typename... Us2>
requires(sizeof...(Us1) == sizeof...(Us2))
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const type_list<Us1...>&, const type_list<Us2...>&)
{
return (... && have_same_canonical_reference_unit_impl(Us1{}, Us2{}));
}
template<typename... Expr1, typename... Expr2>
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const derived_unit<Expr1...>&,
const derived_unit<Expr2...>&)
{
return have_same_canonical_reference_unit_impl(typename derived_unit<Expr1...>::_num_{},
typename derived_unit<Expr2...>::_num_{}) &&
have_same_canonical_reference_unit_impl(typename derived_unit<Expr1...>::_den_{},
typename derived_unit<Expr2...>::_den_{});
}
[[nodiscard]] consteval bool have_same_canonical_reference_unit(Unit auto u1, Unit auto u2)
{
auto canonical_lhs = get_canonical_unit(u1);
auto canonical_rhs = get_canonical_unit(u2);
return have_same_canonical_reference_unit_impl(canonical_lhs.reference_unit, canonical_rhs.reference_unit);
if constexpr (is_same_v<U1, U2>)
return true;
else
return is_same_v<decltype(get_canonical_unit(u1).reference_unit), decltype(get_canonical_unit(u2).reference_unit)>;
}
} // namespace detail
@ -621,17 +600,21 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
// common dimensionless units
// clang-format off
inline constexpr struct percent : named_unit<"%", mag_ratio<1, 100> * one> {} percent;
inline constexpr struct per_mille : named_unit<symbol_text{u8"", "%o"}, mag_ratio<1, 1000> * one> {} per_mille;
inline constexpr struct parts_per_million : named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {} parts_per_million;
inline constexpr struct percent final : named_unit<"%", mag_ratio<1, 100> * one> {} percent;
inline constexpr struct per_mille final : named_unit<symbol_text{u8"", "%o"}, mag_ratio<1, 1000> * one> {} per_mille;
inline constexpr struct parts_per_million final : named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {} parts_per_million;
inline constexpr auto ppm = parts_per_million;
// clang-format on
// convertible_to
[[nodiscard]] consteval bool convertible(Unit auto from, Unit auto to)
template<Unit U1, Unit U2>
[[nodiscard]] consteval bool convertible(U1 from, U2 to)
{
return detail::have_same_canonical_reference_unit(from, to);
if constexpr (is_same_v<U1, U2>)
return true;
else
return detail::have_same_canonical_reference_unit(from, to);
}
// Common unit
@ -641,10 +624,12 @@ template<Unit U1, Unit U2>
[[nodiscard]] consteval Unit auto common_unit(U1 u1, U2 u2)
requires(detail::have_same_canonical_reference_unit(u1, u2))
{
if constexpr (U1{} == U2{}) {
if constexpr (std::derived_from<U1, U2>)
if constexpr (is_same_v<U1, U2>)
return u1;
else if constexpr (U1{} == U2{}) {
if constexpr (std::derived_from<U1, typename U2::_base_type_>)
return u1;
else if constexpr (std::derived_from<U2, U1>)
else if constexpr (std::derived_from<U2, typename U1::_base_type_>)
return u2;
else
// TODO Check if there is a better choice here
@ -738,7 +723,7 @@ constexpr Out unit_symbol_impl(Out out, U, const unit_symbol_formatting& fmt, bo
}
template<typename CharT, std::output_iterator<CharT> Out, auto M, typename U>
constexpr Out unit_symbol_impl(Out out, const scaled_unit<M, U>& u, const unit_symbol_formatting& fmt,
constexpr Out unit_symbol_impl(Out out, const scaled_unit_impl<M, U>& u, const unit_symbol_formatting& fmt,
bool negative_power)
{
if constexpr (M == mag<1>) {
@ -807,13 +792,13 @@ constexpr Out unit_symbol_impl(Out out, const type_list<Nums...>& nums, const ty
}
template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, const unit_symbol_formatting& fmt,
constexpr Out unit_symbol_impl(Out out, const derived_unit_impl<Expr...>&, const unit_symbol_formatting& fmt,
bool negative_power)
{
(void)negative_power;
MP_UNITS_EXPECTS(negative_power == false);
return unit_symbol_impl<CharT>(out, typename derived_unit<Expr...>::_num_{}, typename derived_unit<Expr...>::_den_{},
fmt);
return unit_symbol_impl<CharT>(out, typename derived_unit_impl<Expr...>::_num_{},
typename derived_unit_impl<Expr...>::_den_{}, fmt);
}
} // namespace detail

View File

@ -33,9 +33,8 @@ namespace mp_units {
namespace detail {
// do not refactor below to a variable template - GCC-11 does not like it
template<typename T>
struct is_unit : std::false_type {};
inline constexpr bool is_unit = false;
} // namespace detail
@ -45,7 +44,7 @@ struct is_unit : std::false_type {};
* Satisfied by all unit types provided by the library.
*/
MP_UNITS_EXPORT template<typename T>
concept Unit = detail::is_unit<T>::value;
concept Unit = detail::is_unit<T>;
template<Magnitude auto M, Unit U>
struct scaled_unit;
@ -53,6 +52,8 @@ struct scaled_unit;
MP_UNITS_EXPORT template<symbol_text Symbol, auto...>
struct named_unit;
MP_UNITS_EXPORT struct one;
namespace detail {
template<symbol_text Symbol, auto... Args>
@ -127,25 +128,17 @@ void is_unit_impl(const scaled_unit<M, U>*);
template<symbol_text Symbol, auto... Args>
void is_unit_impl(const named_unit<Symbol, Args...>*);
template<symbol_text Symbol, auto M, auto U>
void is_unit_impl(const prefixed_unit<Symbol, M, U>*);
template<typename... Expr>
void is_unit_impl(const derived_unit<Expr...>*);
template<typename T>
inline constexpr bool is_specialization_of_unit = false;
template<symbol_text Symbol, auto... Args>
inline constexpr bool is_specialization_of_unit<named_unit<Symbol, Args...>> = true;
void is_unit_impl(const one*);
template<typename T>
inline constexpr bool is_specialization_of_prefixed_unit = false;
template<symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
inline constexpr bool is_specialization_of_prefixed_unit<prefixed_unit<Symbol, M, U>> = true;
template<typename T>
requires requires(T* t) { is_unit_impl(t); } && (!is_specialization_of_named_unit<T>) &&
(!is_specialization_of_prefixed_unit<T>)
struct is_unit<T> : std::true_type {};
requires requires(T* t) { is_unit_impl(t); } && std::is_final_v<T>
inline constexpr bool is_unit<T> = true;
template<Unit U>
[[nodiscard]] consteval bool has_associated_quantity(U);
@ -197,7 +190,8 @@ concept UnitOf =
namespace detail {
[[nodiscard]] consteval bool have_same_canonical_reference_unit(Unit auto u1, Unit auto u2);
template<Unit U1, Unit U2>
[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2);
}
@ -210,7 +204,7 @@ namespace detail {
MP_UNITS_EXPORT template<typename U, auto U2, auto QS>
concept UnitCompatibleWith =
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
(!AssociatedUnit<U> || UnitOf<U, QS>)&&detail::have_same_canonical_reference_unit(U{}, U2);
(!AssociatedUnit<U> || UnitOf<U, QS>)&&(detail::have_same_canonical_reference_unit(U{}, U2));
} // namespace mp_units

View File

@ -1,3 +1,25 @@
// 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.
module;
#include <mp-units/bits/core_gmf.h>

View File

@ -1,3 +1,25 @@
// 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.
module;
export module mp_units;

View File

@ -34,15 +34,15 @@ MP_UNITS_EXPORT
namespace mp_units::angular {
// clang-format off
inline constexpr struct dim_angle : base_dimension<"A"> {} dim_angle;
inline constexpr struct dim_angle final : base_dimension<"A"> {} dim_angle;
QUANTITY_SPEC(angle, dim_angle);
QUANTITY_SPEC(solid_angle, pow<2>(angle));
inline constexpr struct radian : named_unit<"rad", kind_of<angle>> {} radian;
inline constexpr struct revolution : named_unit<"rev", mag<2> * mag_pi * radian> {} revolution;
inline constexpr struct degree : named_unit<symbol_text{u8"°", "deg"}, mag_ratio<1, 360> * revolution> {} degree;
inline constexpr struct gradian : named_unit<symbol_text{u8"", "grad"}, mag_ratio<1, 400> * revolution> {} gradian;
inline constexpr struct steradian : named_unit<"sr", square(radian)> {} steradian;
inline constexpr struct radian final : named_unit<"rad", kind_of<angle>> {} radian;
inline constexpr struct revolution final : named_unit<"rev", mag<2> * mag_pi * radian> {} revolution;
inline constexpr struct degree final : named_unit<symbol_text{u8"°", "deg"}, mag_ratio<1, 360> * revolution> {} degree;
inline constexpr struct gradian final : named_unit<symbol_text{u8"", "grad"}, mag_ratio<1, 400> * revolution> {} gradian;
inline constexpr struct steradian final : named_unit<"sr", square(radian)> {} steradian;
// clang-format on
namespace unit_symbols {

View File

@ -35,20 +35,16 @@ MP_UNITS_EXPORT
namespace mp_units::cgs {
// clang-format off
#if MP_UNITS_COMP_MSVC
inline constexpr struct centimetre : si::centi_<si::metre> {} centimetre;
#else
inline constexpr struct centimetre : decltype(si::centi<si::metre>) {} centimetre;
#endif
inline constexpr struct gram : decltype(si::gram) {} gram;
inline constexpr struct second : decltype(si::second) {} second;
inline constexpr struct gal : named_unit<"Gal", centimetre / square(second)> {} gal;
inline constexpr struct dyne : named_unit<"dyn", gram * centimetre / square(second)> {} dyne;
inline constexpr struct erg : named_unit<"erg", dyne * centimetre> {} erg;
inline constexpr struct barye : named_unit<"Ba", gram / (centimetre * square(second))> {} barye;
inline constexpr struct poise : named_unit<"P", gram / (centimetre * second)> {} poise;
inline constexpr struct stokes : named_unit<"St", square(centimetre) / second> {} stokes;
inline constexpr struct kayser : named_unit<"K", one / centimetre> {} kayser;
inline constexpr auto centimetre = si::centi<si::metre>;
inline constexpr auto gram = si::gram;
inline constexpr auto second = si::second;
inline constexpr struct gal final : named_unit<"Gal", centimetre / square(second)> {} gal;
inline constexpr struct dyne final : named_unit<"dyn", gram * centimetre / square(second)> {} dyne;
inline constexpr struct erg final : named_unit<"erg", dyne * centimetre> {} erg;
inline constexpr struct barye final : named_unit<"Ba", gram / (centimetre * square(second))> {} barye;
inline constexpr struct poise final : named_unit<"P", gram / (centimetre * second)> {} poise;
inline constexpr struct stokes final : named_unit<"St", square(centimetre) / second> {} stokes;
inline constexpr struct kayser final : named_unit<"K", one / centimetre> {} kayser;
// clang-format on
namespace unit_symbols {

View File

@ -49,15 +49,15 @@ using si::electronvolt;
// effective cross-sectional area according to EU council directive 80/181/EEC
// https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:01980L0181-20090527#page=10
// https://www.fedlex.admin.ch/eli/cc/1994/3109_3109_3109/de
inline constexpr struct barn : named_unit<"b", mag_power<10, -28> * square(si::metre)> {} barn;
inline constexpr struct barn final : named_unit<"b", mag_power<10, -28> * square(si::metre)> {} barn;
// mass
inline constexpr struct electron_mass : named_unit<"m_e", mag_ratio<9'109'383'701'528, 1'000'000'000'000> * mag_power<10, -31> * si::kilogram> {} electron_mass;
inline constexpr struct proton_mass : named_unit<"m_p", mag_ratio<1'672'621'923'695, 1'000'000'000'000> * mag_power<10, -27> * si::kilogram> {} proton_mass;
inline constexpr struct neutron_mass : named_unit<"m_n", mag_ratio<1'674'927'498'049, 1'000'000'000'000> * mag_power<10, -27> * si::kilogram> {} neutron_mass;
inline constexpr struct electron_mass final : named_unit<"m_e", mag_ratio<9'109'383'701'528, 1'000'000'000'000> * mag_power<10, -31> * si::kilogram> {} electron_mass;
inline constexpr struct proton_mass final : named_unit<"m_p", mag_ratio<1'672'621'923'695, 1'000'000'000'000> * mag_power<10, -27> * si::kilogram> {} proton_mass;
inline constexpr struct neutron_mass final : named_unit<"m_n", mag_ratio<1'674'927'498'049, 1'000'000'000'000> * mag_power<10, -27> * si::kilogram> {} neutron_mass;
// speed
inline constexpr struct speed_of_light : decltype(si::si2019::speed_of_light_in_vacuum) {} speed_of_light;
inline constexpr auto speed_of_light = si::si2019::speed_of_light_in_vacuum;
// clang-format on
namespace unit_symbols {

View File

@ -39,43 +39,43 @@ namespace mp_units::iau {
// clang-format off
// time
inline constexpr struct day : named_unit<"D", si::day> {} day;
inline constexpr struct Julian_year : named_unit<"a", mag_ratio<365'25, 100> * day> {} Julian_year;
inline constexpr struct day final : named_unit<"D", si::day> {} day;
inline constexpr struct Julian_year final : named_unit<"a", mag_ratio<365'25, 100> * day> {} Julian_year;
// mass
// https://en.wikipedia.org/wiki/Solar_mass
// TODO What is the official mass of sun (every source in the Internet provides a different value)
inline constexpr struct solar_mass : named_unit<symbol_text{u8"M_☉", "M_SUN"}, mag_ratio<198'847, 100'000> * mag_power<10, 30> * si::kilogram> {} solar_mass;
inline constexpr struct Jupiter_mass : named_unit<"M_JUP", mag_ratio<1'898, 1'000> * mag_power<10, 27> * si::kilogram> {} Jupiter_mass;
inline constexpr struct Earth_mass : named_unit<"M_EARTH", mag_ratio<59'742, 10'000> * mag_power<10, 24> * si::kilogram> {} Earth_mass;
inline constexpr struct solar_mass final : named_unit<symbol_text{u8"M_☉", "M_SUN"}, mag_ratio<198'847, 100'000> * mag_power<10, 30> * si::kilogram> {} solar_mass;
inline constexpr struct Jupiter_mass final : named_unit<"M_JUP", mag_ratio<1'898, 1'000> * mag_power<10, 27> * si::kilogram> {} Jupiter_mass;
inline constexpr struct Earth_mass final : named_unit<"M_EARTH", mag_ratio<59'742, 10'000> * mag_power<10, 24> * si::kilogram> {} Earth_mass;
// length
inline constexpr struct astronomical_unit : decltype(si::astronomical_unit) {} astronomical_unit;
inline constexpr auto astronomical_unit = si::astronomical_unit;
// https://en.wikipedia.org/wiki/Lunar_distance_(astronomy)
inline constexpr struct lunar_distance : named_unit<"LD", mag<384'399> * si::kilo<si::metre>> {} lunar_distance;
inline constexpr struct lunar_distance final : named_unit<"LD", mag<384'399> * si::kilo<si::metre>> {} lunar_distance;
// https://en.wikipedia.org/wiki/Light-year
inline constexpr struct light_year : named_unit<"ly", mag<9'460'730'472'580'800> * si::metre> {} light_year;
inline constexpr struct light_year final : named_unit<"ly", mag<9'460'730'472'580'800> * si::metre> {} light_year;
// https://en.wikipedia.org/wiki/Parsec
inline constexpr struct parsec : named_unit<"pc", astronomical_unit / (mag_ratio<1, 3600> * si::degree)> {} parsec;
inline constexpr struct parsec final : named_unit<"pc", astronomical_unit / (mag_ratio<1, 3600> * si::degree)> {} parsec;
// https://en.wikipedia.org/wiki/Angstrom
inline constexpr struct angstrom : named_unit<symbol_text{u8"Å", "A"}, mag_power<10, -10> * si::metre> {} angstrom;
inline constexpr struct angstrom final : named_unit<symbol_text{u8"Å", "A"}, mag_power<10, -10> * si::metre> {} angstrom;
// selected constants
// https://en.wikipedia.org/wiki/Astronomical_constant
inline constexpr struct gaussian_gravitational_constant :
inline constexpr struct gaussian_gravitational_constant final :
named_unit<"k", mag_ratio<1'720'209'895, 100'000'000'000> * pow<3, 2>(astronomical_unit) / pow<1,2>(solar_mass) / day> {} gaussian_gravitational_constant;
inline constexpr struct speed_of_light :
inline constexpr struct speed_of_light final :
named_unit<symbol_text{u8"c₀", "c_0"}, si::si2019::speed_of_light_in_vacuum> {} speed_of_light;
inline constexpr struct constant_of_gravitation :
inline constexpr struct constant_of_gravitation final :
named_unit<"G", mag_ratio<667'430, 100'000> * mag_power<10, -11> * cubic(si::metre) / si::kilogram / square(si::second)> {} constant_of_gravitation;
inline constexpr struct hubble_constant :
inline constexpr struct hubble_constant final :
named_unit<symbol_text{u8"H₀", "H_0"}, mag_ratio<701, 10> * si::kilo<si::metre> / si::second / si::mega<parsec>> {} hubble_constant;
// clang-format on

View File

@ -31,14 +31,14 @@
namespace mp_units::iec80000 {
// clang-format off
template<PrefixableUnit U> struct kibi_ : prefixed_unit<"Ki", mag_power<2, 10>, U{}> {};
template<PrefixableUnit U> struct mebi_ : prefixed_unit<"Mi", mag_power<2, 20>, U{}> {};
template<PrefixableUnit U> struct gibi_ : prefixed_unit<"Gi", mag_power<2, 30>, U{}> {};
template<PrefixableUnit U> struct tebi_ : prefixed_unit<"Ti", mag_power<2, 40>, U{}> {};
template<PrefixableUnit U> struct pebi_ : prefixed_unit<"Pi", mag_power<2, 50>, U{}> {};
template<PrefixableUnit U> struct exbi_ : prefixed_unit<"Ei", mag_power<2, 60>, U{}> {};
template<PrefixableUnit U> struct zebi_ : prefixed_unit<"Zi", mag_power<2, 70>, U{}> {};
template<PrefixableUnit U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U{}> {};
template<PrefixableUnit U> struct kibi_ final : prefixed_unit<"Ki", mag_power<2, 10>, U{}> {};
template<PrefixableUnit U> struct mebi_ final : prefixed_unit<"Mi", mag_power<2, 20>, U{}> {};
template<PrefixableUnit U> struct gibi_ final : prefixed_unit<"Gi", mag_power<2, 30>, U{}> {};
template<PrefixableUnit U> struct tebi_ final : prefixed_unit<"Ti", mag_power<2, 40>, U{}> {};
template<PrefixableUnit U> struct pebi_ final : prefixed_unit<"Pi", mag_power<2, 50>, U{}> {};
template<PrefixableUnit U> struct exbi_ final : prefixed_unit<"Ei", mag_power<2, 60>, U{}> {};
template<PrefixableUnit U> struct zebi_ final : prefixed_unit<"Zi", mag_power<2, 70>, U{}> {};
template<PrefixableUnit U> struct yobi_ final : prefixed_unit<"Yi", mag_power<2, 80>, U{}> {};
MP_UNITS_EXPORT_BEGIN

View File

@ -36,7 +36,7 @@ namespace mp_units::iec80000 {
// dimensions of base quantities
// clang-format off
inline constexpr struct dim_traffic_intensity : base_dimension<"A"> {} dim_traffic_intensity;
inline constexpr struct dim_traffic_intensity final : base_dimension<"A"> {} dim_traffic_intensity;
// clang-format on
// quantities

View File

@ -34,11 +34,11 @@ MP_UNITS_EXPORT
namespace mp_units::iec80000 {
// clang-format off
inline constexpr struct erlang : named_unit<"E", kind_of<traffic_intensity>> {} erlang;
inline constexpr struct bit : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
inline constexpr struct octet : named_unit<"o", mag<8> * bit> {} octet;
inline constexpr struct byte : named_unit<"B", mag<8> * bit> {} byte;
inline constexpr struct baud : named_unit<"Bd", one / si::second, kind_of<modulation_rate>> {} baud;
inline constexpr struct erlang final : named_unit<"E", kind_of<traffic_intensity>> {} erlang;
inline constexpr struct bit final : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
inline constexpr struct octet final : named_unit<"o", mag<8> * bit> {} octet;
inline constexpr struct byte final : named_unit<"B", mag<8> * bit> {} byte;
inline constexpr struct baud final : named_unit<"Bd", one / si::second, kind_of<modulation_rate>> {} baud;
// clang-format on
} // namespace mp_units::iec80000

View File

@ -39,38 +39,38 @@ using namespace international;
// clang-format off
// https://en.wikipedia.org/wiki/Imperial_units#Length
inline constexpr struct hand : named_unit<"hh", mag_ratio<1, 3> * foot> {} hand;
inline constexpr struct barleycorn : named_unit<"Bc", mag_ratio<1, 3> * inch> {} barleycorn;
inline constexpr struct thou : named_unit<"th", mag_ratio<1, 12'000> * foot> {} thou;
inline constexpr struct chain : named_unit<"ch", mag<22> * yard> {} chain;
inline constexpr struct furlong : named_unit<"fur", mag<10> * chain> {} furlong;
inline constexpr struct hand final : named_unit<"hh", mag_ratio<1, 3> * foot> {} hand;
inline constexpr struct barleycorn final : named_unit<"Bc", mag_ratio<1, 3> * inch> {} barleycorn;
inline constexpr struct thou final : named_unit<"th", mag_ratio<1, 12'000> * foot> {} thou;
inline constexpr struct chain final : named_unit<"ch", mag<22> * yard> {} chain;
inline constexpr struct furlong final : named_unit<"fur", mag<10> * chain> {} furlong;
// maritime units
inline constexpr struct cable : named_unit<"cb", mag_ratio<1, 10> * nautical_mile> {} cable;
inline constexpr struct fathom : named_unit<"ftm", mag_ratio<1, 1000> * nautical_mile> {} fathom;
inline constexpr struct cable final : named_unit<"cb", mag_ratio<1, 10> * nautical_mile> {} cable;
inline constexpr struct fathom final : named_unit<"ftm", mag_ratio<1, 1000> * nautical_mile> {} fathom;
// survey
inline constexpr struct link : named_unit<"li", mag_ratio<1, 100> * chain> {} link;
inline constexpr struct rod : named_unit<"rd", mag<25> * link> {} rod;
inline constexpr struct link final : named_unit<"li", mag_ratio<1, 100> * chain> {} link;
inline constexpr struct rod final : named_unit<"rd", mag<25> * link> {} rod;
// https://en.wikipedia.org/wiki/Imperial_units#Area
inline constexpr struct perch : decltype(square(rod)) {} perch;
inline constexpr struct rood : decltype(mag<40> * perch) {} rood;
inline constexpr struct acre : decltype(mag<4> * rood) {} acre;
inline constexpr struct perch final : named_unit<"perch", square(rod)> {} perch;
inline constexpr struct rood final : named_unit<"rood", mag<40> * perch> {} rood;
inline constexpr struct acre final : named_unit<"acre", mag<4> * rood> {} acre;
// https://en.wikipedia.org/wiki/Imperial_units#Volume
inline constexpr struct gallon : named_unit<"gal", mag_ratio<454'609, 100'000> * si::litre> {} gallon;
inline constexpr struct quart : named_unit<"qt", mag_ratio<1, 4> * gallon> {} quart;
inline constexpr struct pint : named_unit<"pt", mag_ratio<1, 2> * quart> {} pint;
inline constexpr struct gill : named_unit<"gi", mag_ratio<1, 4> * pint> {} gill;
inline constexpr struct fluid_ounce : named_unit<"fl oz", mag_ratio<1, 5> * gill> {} fluid_ounce;
inline constexpr struct gallon final : named_unit<"gal", mag_ratio<454'609, 100'000> * si::litre> {} gallon;
inline constexpr struct quart final : named_unit<"qt", mag_ratio<1, 4> * gallon> {} quart;
inline constexpr struct pint final : named_unit<"pt", mag_ratio<1, 2> * quart> {} pint;
inline constexpr struct gill final : named_unit<"gi", mag_ratio<1, 4> * pint> {} gill;
inline constexpr struct fluid_ounce final : named_unit<"fl oz", mag_ratio<1, 5> * gill> {} fluid_ounce;
// https://en.wikipedia.org/wiki/Avoirdupois_system#Post-Elizabethan_units
inline constexpr auto drachm = dram;
inline constexpr struct stone : named_unit<"st", mag<14> * pound> {} stone;
inline constexpr struct quarter : named_unit<"qr", mag<2> * stone> {} quarter;
inline constexpr struct long_hundredweight : named_unit<"cwt", mag<8> * stone> {} long_hundredweight;
inline constexpr struct ton : named_unit<"t", mag<2'240> * pound> {} ton;
inline constexpr struct stone final : named_unit<"st", mag<14> * pound> {} stone;
inline constexpr struct quarter final : named_unit<"qr", mag<2> * stone> {} quarter;
inline constexpr struct long_hundredweight final : named_unit<"cwt", mag<8> * stone> {} long_hundredweight;
inline constexpr struct ton final : named_unit<"t", mag<2'240> * pound> {} ton;
inline constexpr auto long_ton = ton;
// clang-format on

View File

@ -37,48 +37,44 @@ namespace mp_units::international {
// clang-format off
// mass
inline constexpr struct pound : named_unit<"lb", mag_ratio<45'359'237, 100'000'000> * si::kilogram> {} pound;
inline constexpr struct ounce : named_unit<"oz", mag_ratio<1, 16> * pound> {} ounce;
inline constexpr struct dram : named_unit<"dr", mag_ratio<1, 16> * ounce> {} dram;
inline constexpr struct grain : named_unit<"gr", mag_ratio<1, 7'000> * pound> {} grain;
inline constexpr struct pound final : named_unit<"lb", mag_ratio<45'359'237, 100'000'000> * si::kilogram> {} pound;
inline constexpr struct ounce final : named_unit<"oz", mag_ratio<1, 16> * pound> {} ounce;
inline constexpr struct dram final : named_unit<"dr", mag_ratio<1, 16> * ounce> {} dram;
inline constexpr struct grain final : named_unit<"gr", mag_ratio<1, 7'000> * pound> {} grain;
// length
// https://en.wikipedia.org/wiki/United_States_customary_units#Length
inline constexpr struct yard : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct foot : named_unit<"ft", mag_ratio<1, 3> * yard> {} foot;
inline constexpr struct inch : named_unit<"in", mag_ratio<1, 12> * foot> {} inch;
inline constexpr struct pica : named_unit<"P", mag_ratio<1, 6> * inch> {} pica;
inline constexpr struct point : named_unit<"p", mag_ratio<1, 12> * pica> {} point;
inline constexpr struct mil : named_unit<"mil", mag_ratio<1, 1'000> * inch> {} mil;
inline constexpr struct twip : named_unit<"twip", mag_ratio<1, 20> * point> {} twip;
inline constexpr struct mile : named_unit<"mi", mag<1760> * yard> {} mile;
inline constexpr struct league : named_unit<"le", mag<3> * mile> {} league;
inline constexpr struct yard final : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct foot final : named_unit<"ft", mag_ratio<1, 3> * yard> {} foot;
inline constexpr struct inch final : named_unit<"in", mag_ratio<1, 12> * foot> {} inch;
inline constexpr struct pica final : named_unit<"P", mag_ratio<1, 6> * inch> {} pica;
inline constexpr struct point final : named_unit<"p", mag_ratio<1, 12> * pica> {} point;
inline constexpr struct mil final : named_unit<"mil", mag_ratio<1, 1'000> * inch> {} mil;
inline constexpr struct twip final : named_unit<"twip", mag_ratio<1, 20> * point> {} twip;
inline constexpr struct mile final : named_unit<"mi", mag<1760> * yard> {} mile;
inline constexpr struct league final : named_unit<"le", mag<3> * mile> {} league;
inline constexpr struct nautical_mile : named_unit<"nmi", mag<1852> * si::metre> {} nautical_mile;
inline constexpr struct nautical_mile final : named_unit<"nmi", mag<1852> * si::metre> {} nautical_mile;
// speed
inline constexpr struct knot : named_unit<"kn", nautical_mile / si::hour> {} knot;
inline constexpr struct knot final : named_unit<"kn", nautical_mile / si::hour> {} knot;
// force
// https://en.wikipedia.org/wiki/Poundal
inline constexpr struct poundal : named_unit<"pdl", pound * foot / square(si::second)> {} poundal;
inline constexpr struct poundal final : named_unit<"pdl", pound * foot / square(si::second)> {} poundal;
// https://en.wikipedia.org/wiki/Pound_(force)
inline constexpr struct pound_force : named_unit<"lbf", pound * si::standard_gravity> {} pound_force;
inline constexpr struct pound_force final : named_unit<"lbf", pound * si::standard_gravity> {} pound_force;
// https://en.wikipedia.org/wiki/Kip_(unit),
#if MP_UNITS_COMP_MSVC
inline constexpr struct kip : si::kilo_<pound_force> {} kip;
#else
inline constexpr struct kip : decltype(si::kilo<pound_force>) {} kip;
#endif
inline constexpr auto kip = si::kilo<pound_force>;
// pressure
inline constexpr struct psi : named_unit<"psi", pound_force / square(inch)> {} psi;
inline constexpr struct psi final : named_unit<"psi", pound_force / square(inch)> {} psi;
// power
// https://en.wikipedia.org/wiki/Horsepower#Definitions
inline constexpr struct mechanical_horsepower : named_unit<"hp(I)", mag<33'000> * foot * pound_force / si::minute> {} mechanical_horsepower;
inline constexpr struct mechanical_horsepower final : named_unit<"hp(I)", mag<33'000> * foot * pound_force / si::minute> {} mechanical_horsepower;
// clang-format on

View File

@ -35,13 +35,13 @@ namespace mp_units::isq {
// clang-format off
// dimensions of base quantities
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_electric_current : base_dimension<"I"> {} dim_electric_current;
inline constexpr struct dim_thermodynamic_temperature : base_dimension<symbol_text{u8"Θ", "O"}> {} dim_thermodynamic_temperature;
inline constexpr struct dim_amount_of_substance : base_dimension<"N"> {} dim_amount_of_substance;
inline constexpr struct dim_luminous_intensity : base_dimension<"J"> {} dim_luminous_intensity;
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass final : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_electric_current final : base_dimension<"I"> {} dim_electric_current;
inline constexpr struct dim_thermodynamic_temperature final : base_dimension<symbol_text{u8"Θ", "O"}> {} dim_thermodynamic_temperature;
inline constexpr struct dim_amount_of_substance final : base_dimension<"N"> {} dim_amount_of_substance;
inline constexpr struct dim_luminous_intensity final : base_dimension<"J"> {} dim_luminous_intensity;
// clang-format on
// base quantities

View File

@ -38,12 +38,8 @@ namespace mp_units::natural {
// clang-format off
// units
inline constexpr struct electronvolt : named_unit<"eV"> {} electronvolt;
#if MP_UNITS_COMP_MSVC
inline constexpr struct gigaelectronvolt : si::giga_<electronvolt> {} gigaelectronvolt;
#else
inline constexpr struct gigaelectronvolt : decltype(si::giga<electronvolt>) {} gigaelectronvolt;
#endif
inline constexpr struct electronvolt final : named_unit<"eV"> {} electronvolt;
inline constexpr auto gigaelectronvolt = si::giga<electronvolt>;
// system references
inline constexpr struct time : system_reference<isq::time, inverse(gigaelectronvolt)> {} time;

View File

@ -85,7 +85,7 @@ struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
};
template<typename C>
struct chrono_point_origin_ : absolute_point_origin<chrono_point_origin_<C>, isq::time> {
struct chrono_point_origin_ final : absolute_point_origin<isq::time> {
using clock = C;
};
MP_UNITS_EXPORT template<typename C>
@ -113,12 +113,20 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
}
};
namespace detail {
[[nodiscard]] constexpr auto as_ratio(Magnitude auto m)
requires(is_rational(m))
{
return std::ratio<get_value<std::intmax_t>(numerator(m)), get_value<std::intmax_t>(denominator(m))>{};
}
} // namespace detail
template<QuantityOf<isq::time> Q>
[[nodiscard]] constexpr auto to_chrono_duration(const Q& q)
{
constexpr auto canonical = get_canonical_unit(Q::unit);
constexpr detail::ratio r = detail::as_ratio(canonical.mag);
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q};
return std::chrono::duration<typename Q::rep, decltype(detail::as_ratio(get_canonical_unit(Q::unit).mag))>{q};
}
template<QuantityPointOf<isq::time> QP>
@ -127,9 +135,9 @@ template<QuantityPointOf<isq::time> QP>
{
using clock = MP_UNITS_TYPENAME decltype(QP::absolute_point_origin)::clock;
using rep = MP_UNITS_TYPENAME QP::rep;
constexpr auto canonical = get_canonical_unit(QP::unit);
constexpr detail::ratio r = detail::as_ratio(canonical.mag);
using ret_type = std::chrono::time_point<clock, std::chrono::duration<rep, std::ratio<r.num, r.den>>>;
using ret_type =
std::chrono::time_point<clock,
std::chrono::duration<rep, decltype(detail::as_ratio(get_canonical_unit(QP::unit).mag))>>;
return ret_type(to_chrono_duration(qp - qp.absolute_point_origin));
}

View File

@ -35,28 +35,28 @@ namespace mp_units::si {
namespace si2019 {
// clang-format off
inline constexpr struct hyperfine_structure_transition_frequency_of_cs :
inline constexpr struct hyperfine_structure_transition_frequency_of_cs final :
named_unit<symbol_text{u8"Δν_Cs", "dv_Cs"}, mag<9'192'631'770> * hertz> {} hyperfine_structure_transition_frequency_of_cs;
inline constexpr struct speed_of_light_in_vacuum :
inline constexpr struct speed_of_light_in_vacuum final :
named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct planck_constant :
inline constexpr struct planck_constant final :
named_unit<"h", mag_ratio<662'607'015, 100'000'000> * mag_power<10, -34> * joule * second> {} planck_constant;
inline constexpr struct elementary_charge :
inline constexpr struct elementary_charge final :
named_unit<"e", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * coulomb> {} elementary_charge;
inline constexpr struct boltzmann_constant :
inline constexpr struct boltzmann_constant final :
named_unit<"k", mag_ratio<1'380'649, 1'000'000> * mag_power<10, -23> * joule / kelvin> {} boltzmann_constant;
inline constexpr struct avogadro_constant :
inline constexpr struct avogadro_constant final :
named_unit<"N_A", mag_ratio<602'214'076, 100'000'000> * mag_power<10, 23> / mole> {} avogadro_constant;
inline constexpr struct luminous_efficacy :
inline constexpr struct luminous_efficacy final :
named_unit<"K_cd", mag<683> * lumen / watt> {} luminous_efficacy;
// clang-format on
} // namespace si2019
// clang-format off
inline constexpr struct standard_gravity :
inline constexpr struct standard_gravity final :
named_unit<symbol_text{u8"g₀", "g_0"}, mag_ratio<980'665, 100'000> * metre / square(second)> {} standard_gravity;
inline constexpr struct magnetic_constant :
inline constexpr struct magnetic_constant final :
named_unit<symbol_text{u8"μ₀", "u_0"}, mag<4> * mag_pi * mag_power<10, -7> * henry / metre> {} magnetic_constant;
// clang-format on

View File

@ -31,30 +31,30 @@
namespace mp_units::si {
// clang-format off
template<PrefixableUnit U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U{}> {};
template<PrefixableUnit U> struct ronto_ : prefixed_unit<"r", mag_power<10, -27>, U{}> {};
template<PrefixableUnit U> struct yocto_ : prefixed_unit<"y", mag_power<10, -24>, U{}> {};
template<PrefixableUnit U> struct zepto_ : prefixed_unit<"z", mag_power<10, -21>, U{}> {};
template<PrefixableUnit U> struct atto_ : prefixed_unit<"a", mag_power<10, -18>, U{}> {};
template<PrefixableUnit U> struct femto_ : prefixed_unit<"f", mag_power<10, -15>, U{}> {};
template<PrefixableUnit U> struct pico_ : prefixed_unit<"p", mag_power<10, -12>, U{}> {};
template<PrefixableUnit U> struct nano_ : prefixed_unit<"n", mag_power<10, -9>, U{}> {};
template<PrefixableUnit U> struct micro_ : prefixed_unit<symbol_text{u8"µ", "u"}, mag_power<10, -6>, U{}> {};
template<PrefixableUnit U> struct milli_ : prefixed_unit<"m", mag_power<10, -3>, U{}> {};
template<PrefixableUnit U> struct centi_ : prefixed_unit<"c", mag_power<10, -2>, U{}> {};
template<PrefixableUnit U> struct deci_ : prefixed_unit<"d", mag_power<10, -1>, U{}> {};
template<PrefixableUnit U> struct deca_ : prefixed_unit<"da", mag_power<10, 1>, U{}> {};
template<PrefixableUnit U> struct hecto_ : prefixed_unit<"h", mag_power<10, 2>, U{}> {};
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
template<PrefixableUnit U> struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U{}> {};
template<PrefixableUnit U> struct giga_ : prefixed_unit<"G", mag_power<10, 9>, U{}> {};
template<PrefixableUnit U> struct tera_ : prefixed_unit<"T", mag_power<10, 12>, U{}> {};
template<PrefixableUnit U> struct peta_ : prefixed_unit<"P", mag_power<10, 15>, U{}> {};
template<PrefixableUnit U> struct exa_ : prefixed_unit<"E", mag_power<10, 18>, U{}> {};
template<PrefixableUnit U> struct zetta_ : prefixed_unit<"Z", mag_power<10, 21>, U{}> {};
template<PrefixableUnit U> struct yotta_ : prefixed_unit<"Y", mag_power<10, 24>, U{}> {};
template<PrefixableUnit U> struct ronna_ : prefixed_unit<"R", mag_power<10, 27>, U{}> {};
template<PrefixableUnit U> struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>, U{}> {};
template<PrefixableUnit U> struct quecto_ final : prefixed_unit<"q", mag_power<10, -30>, U{}> {};
template<PrefixableUnit U> struct ronto_ final : prefixed_unit<"r", mag_power<10, -27>, U{}> {};
template<PrefixableUnit U> struct yocto_ final : prefixed_unit<"y", mag_power<10, -24>, U{}> {};
template<PrefixableUnit U> struct zepto_ final : prefixed_unit<"z", mag_power<10, -21>, U{}> {};
template<PrefixableUnit U> struct atto_ final : prefixed_unit<"a", mag_power<10, -18>, U{}> {};
template<PrefixableUnit U> struct femto_ final : prefixed_unit<"f", mag_power<10, -15>, U{}> {};
template<PrefixableUnit U> struct pico_ final : prefixed_unit<"p", mag_power<10, -12>, U{}> {};
template<PrefixableUnit U> struct nano_ final : prefixed_unit<"n", mag_power<10, -9>, U{}> {};
template<PrefixableUnit U> struct micro_ final : prefixed_unit<symbol_text{u8"µ", "u"}, mag_power<10, -6>, U{}> {};
template<PrefixableUnit U> struct milli_ final : prefixed_unit<"m", mag_power<10, -3>, U{}> {};
template<PrefixableUnit U> struct centi_ final : prefixed_unit<"c", mag_power<10, -2>, U{}> {};
template<PrefixableUnit U> struct deci_ final : prefixed_unit<"d", mag_power<10, -1>, U{}> {};
template<PrefixableUnit U> struct deca_ final : prefixed_unit<"da", mag_power<10, 1>, U{}> {};
template<PrefixableUnit U> struct hecto_ final : prefixed_unit<"h", mag_power<10, 2>, U{}> {};
template<PrefixableUnit U> struct kilo_ final : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
template<PrefixableUnit U> struct mega_ final : prefixed_unit<"M", mag_power<10, 6>, U{}> {};
template<PrefixableUnit U> struct giga_ final : prefixed_unit<"G", mag_power<10, 9>, U{}> {};
template<PrefixableUnit U> struct tera_ final : prefixed_unit<"T", mag_power<10, 12>, U{}> {};
template<PrefixableUnit U> struct peta_ final : prefixed_unit<"P", mag_power<10, 15>, U{}> {};
template<PrefixableUnit U> struct exa_ final : prefixed_unit<"E", mag_power<10, 18>, U{}> {};
template<PrefixableUnit U> struct zetta_ final : prefixed_unit<"Z", mag_power<10, 21>, U{}> {};
template<PrefixableUnit U> struct yotta_ final : prefixed_unit<"Y", mag_power<10, 24>, U{}> {};
template<PrefixableUnit U> struct ronna_ final : prefixed_unit<"R", mag_power<10, 27>, U{}> {};
template<PrefixableUnit U> struct quetta_ final : prefixed_unit<"Q", mag_power<10, 30>, U{}> {};
MP_UNITS_EXPORT_BEGIN

View File

@ -38,59 +38,55 @@ namespace si {
// clang-format off
// base units
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
#if MP_UNITS_COMP_MSVC
inline constexpr struct kilogram : kilo_<gram> {} kilogram;
#else
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
#endif
inline constexpr struct ampere : named_unit<"A", kind_of<isq::electric_current>> {} ampere;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct gram final : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr auto kilogram = kilo<gram>;
inline constexpr struct ampere final : named_unit<"A", kind_of<isq::electric_current>> {} ampere;
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
inline constexpr struct kelvin : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr auto zeroth_kelvin = absolute_zero;
inline constexpr struct kelvin final : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
inline constexpr struct mole : named_unit<"mol", kind_of<isq::amount_of_substance>> {} mole;
inline constexpr struct candela : named_unit<"cd", kind_of<isq::luminous_intensity>> {} candela;
inline constexpr struct mole final : named_unit<"mol", kind_of<isq::amount_of_substance>> {} mole;
inline constexpr struct candela final : named_unit<"cd", kind_of<isq::luminous_intensity>> {} candela;
// derived named units
inline constexpr struct radian : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct hertz : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct radian final : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian final : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct hertz final : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
#ifdef pascal
#pragma push_macro("pascal")
#undef pascal
#define MP_UNITS_REDEFINE_PASCAL
#endif
inline constexpr struct pascal : named_unit<"Pa", newton / square(metre)> {} pascal;
inline constexpr struct pascal final : named_unit<"Pa", newton / square(metre)> {} pascal;
#ifdef MP_UNITS_REDEFINE_PASCAL
#pragma pop_macro("pascal")
#undef MP_UNITS_REDEFINE_PASCAL
#endif
inline constexpr struct joule : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt : named_unit<"W", joule / second> {} watt;
inline constexpr struct coulomb : named_unit<"C", ampere * second> {} coulomb;
inline constexpr struct volt : named_unit<"V", watt / ampere> {} volt;
inline constexpr struct farad : named_unit<"F", coulomb / volt> {} farad;
inline constexpr struct ohm : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct siemens : named_unit<"S", one / ohm> {} siemens;
inline constexpr struct weber : named_unit<"Wb", volt * second> {} weber;
inline constexpr struct tesla : named_unit<"T", weber / square(metre)> {} tesla;
inline constexpr struct henry : named_unit<"H", weber / ampere> {} henry;
inline constexpr struct joule final : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt final : named_unit<"W", joule / second> {} watt;
inline constexpr struct coulomb final : named_unit<"C", ampere * second> {} coulomb;
inline constexpr struct volt final : named_unit<"V", watt / ampere> {} volt;
inline constexpr struct farad final : named_unit<"F", coulomb / volt> {} farad;
inline constexpr struct ohm final : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct siemens final : named_unit<"S", one / ohm> {} siemens;
inline constexpr struct weber final : named_unit<"Wb", volt * second> {} weber;
inline constexpr struct tesla final : named_unit<"T", weber / square(metre)> {} tesla;
inline constexpr struct henry final : named_unit<"H", weber / ampere> {} henry;
inline constexpr struct ice_point : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
inline constexpr struct degree_Celsius : named_unit<symbol_text{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
inline constexpr struct ice_point final : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr auto zeroth_degree_Celsius = ice_point;
inline constexpr struct degree_Celsius final : named_unit<symbol_text{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
inline constexpr struct lumen : named_unit<"lm", candela * steradian> {} lumen;
inline constexpr struct lux : named_unit<"lx", lumen / square(metre)> {} lux;
inline constexpr struct becquerel : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
inline constexpr struct gray : named_unit<"Gy", joule / kilogram, kind_of<isq::absorbed_dose>> {} gray;
inline constexpr struct sievert : named_unit<"Sv", joule / kilogram, kind_of<isq::dose_equivalent>> {} sievert;
inline constexpr struct katal : named_unit<"kat", mole / second> {} katal;
inline constexpr struct lumen final : named_unit<"lm", candela * steradian> {} lumen;
inline constexpr struct lux final : named_unit<"lx", lumen / square(metre)> {} lux;
inline constexpr struct becquerel final : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
inline constexpr struct gray final : named_unit<"Gy", joule / kilogram, kind_of<isq::absorbed_dose>> {} gray;
inline constexpr struct sievert final : named_unit<"Sv", joule / kilogram, kind_of<isq::dose_equivalent>> {} sievert;
inline constexpr struct katal final : named_unit<"kat", mole / second> {} katal;
// clang-format on
} // namespace si
@ -99,24 +95,20 @@ namespace non_si {
// clang-format off
// non-SI units accepted for use with the SI
inline constexpr struct minute : named_unit<"min", mag<60> * si::second> {} minute;
inline constexpr struct hour : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct day : named_unit<"d", mag<24> * hour> {} day;
inline constexpr struct astronomical_unit : named_unit<"au", mag<149'597'870'700> * si::metre> {} astronomical_unit;
inline constexpr struct degree : named_unit<symbol_text{u8"°", "deg"}, mag_pi / mag<180> * si::radian> {} degree;
inline constexpr struct arcminute : named_unit<symbol_text{u8"", "'"}, mag_ratio<1, 60> * degree> {} arcminute;
inline constexpr struct arcsecond : named_unit<symbol_text{u8"", "''"}, mag_ratio<1, 60> * arcminute> {} arcsecond;
inline constexpr struct are : named_unit<"a", square(si::deca<si::metre>)> {} are;
#if MP_UNITS_COMP_MSVC
inline constexpr struct hectare : si::hecto_<are> {} hectare;
#else
inline constexpr struct hectare : decltype(si::hecto<are>) {} hectare;
#endif
inline constexpr struct litre : named_unit<"l", cubic(si::deci<si::metre>)> {} litre;
inline constexpr struct tonne : named_unit<"t", mag<1000> * si::kilogram> {} tonne;
inline constexpr struct dalton : named_unit<"Da", mag_ratio<16'605'390'666'050, 10'000'000'000'000> * mag_power<10, -27> * si::kilogram> {} dalton;
inline constexpr struct minute final : named_unit<"min", mag<60> * si::second> {} minute;
inline constexpr struct hour final : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct day final : named_unit<"d", mag<24> * hour> {} day;
inline constexpr struct astronomical_unit final : named_unit<"au", mag<149'597'870'700> * si::metre> {} astronomical_unit;
inline constexpr struct degree final : named_unit<symbol_text{u8"°", "deg"}, mag_pi / mag<180> * si::radian> {} degree;
inline constexpr struct arcminute final : named_unit<symbol_text{u8"", "'"}, mag_ratio<1, 60> * degree> {} arcminute;
inline constexpr struct arcsecond final : named_unit<symbol_text{u8"", "''"}, mag_ratio<1, 60> * arcminute> {} arcsecond;
inline constexpr struct are final : named_unit<"a", square(si::deca<si::metre>)> {} are;
inline constexpr auto hectare = si::hecto<are>;
inline constexpr struct litre final : named_unit<"l", cubic(si::deci<si::metre>)> {} litre;
inline constexpr struct tonne final : named_unit<"t", mag<1000> * si::kilogram> {} tonne;
inline constexpr struct dalton final : named_unit<"Da", mag_ratio<16'605'390'666'050, 10'000'000'000'000> * mag_power<10, -27> * si::kilogram> {} dalton;
// TODO A different value is provided in the SI Brochure and different in the ISO 80000
inline constexpr struct electronvolt : named_unit<"eV", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * si::joule> {} electronvolt;
inline constexpr struct electronvolt final : named_unit<"eV", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * si::joule> {} electronvolt;
// TODO the below are logarithmic units - how to support those?
// neper
// bel

View File

@ -36,11 +36,11 @@ namespace mp_units::typographic {
// clang-format off
// https://en.wikipedia.org/wiki/Point_(typography)
inline constexpr struct pica_us : named_unit<"pica(us)", mag_ratio<166'044, 1'000'000> * international::inch> {} pica_us;
inline constexpr struct point_us : named_unit<"point(us)", mag_ratio<1, 12> * pica_us> {} point_us;
inline constexpr struct pica_us final : named_unit<"pica(us)", mag_ratio<166'044, 1'000'000> * international::inch> {} pica_us;
inline constexpr struct point_us final : named_unit<"point(us)", mag_ratio<1, 12> * pica_us> {} point_us;
inline constexpr struct point_dtp : named_unit<"point(dtp)", mag_ratio<1, 72> * international::inch> {} point_dtp;
inline constexpr struct pica_dtp : named_unit<"pica(dtp)", mag<12> * point_dtp> {} pica_dtp;
inline constexpr struct point_dtp final : named_unit<"point(dtp)", mag_ratio<1, 72> * international::inch> {} point_dtp;
inline constexpr struct pica_dtp final : named_unit<"pica(dtp)", mag<12> * point_dtp> {} pica_dtp;
// clang-format on
} // namespace mp_units::typographic

View File

@ -41,12 +41,12 @@ using namespace international;
// https://en.wikipedia.org/wiki/United_States_customary_units#Length
// nautical
inline constexpr struct fathom : named_unit<"ftm(us)", mag<2> * yard> {} fathom;
inline constexpr struct cable : named_unit<"cb(us)", mag<120> * fathom> {} cable;
inline constexpr struct fathom final : named_unit<"ftm(us)", mag<2> * yard> {} fathom;
inline constexpr struct cable final : named_unit<"cb(us)", mag<120> * fathom> {} cable;
// survey
struct us_survey_foot : named_unit<"ft(us)", mag_ratio<1'200, 3'937> * si::metre> {};
struct us_survey_mile : named_unit<"mi(us)", mag<5280> * us_survey_foot{}> {};
struct us_survey_foot final : named_unit<"ft(us)", mag_ratio<1'200, 3'937> * si::metre> {};
struct us_survey_mile final : named_unit<"mi(us)", mag<5280> * us_survey_foot{}> {};
[[deprecated("In accordance with NIST SP 811, as of January 1, 2023, the use of the U.S. survey foot and U.S. survey mile is deprecated.")]]
inline constexpr us_survey_foot us_survey_foot;
@ -54,72 +54,72 @@ inline constexpr us_survey_foot us_survey_foot;
[[deprecated("In accordance with NIST SP 811, as of January 1, 2023, the use of the U.S. survey foot and U.S. survey mile is deprecated.")]]
inline constexpr us_survey_mile us_survey_mile;
inline constexpr struct link : named_unit<"li", mag_ratio<33, 50> * foot> {} link;
inline constexpr struct rod : named_unit<"rd", mag<25> * link> {} rod;
inline constexpr struct chain : named_unit<"ch", mag<4> * rod> {} chain;
inline constexpr struct furlong : named_unit<"fur", mag<10> * chain> {} furlong;
inline constexpr struct link final : named_unit<"li", mag_ratio<33, 50> * foot> {} link;
inline constexpr struct rod final : named_unit<"rd", mag<25> * link> {} rod;
inline constexpr struct chain final : named_unit<"ch", mag<4> * rod> {} chain;
inline constexpr struct furlong final : named_unit<"fur", mag<10> * chain> {} furlong;
// clang-format on
namespace survey1893 {
// clang-format off
inline constexpr struct us_survey_foot : named_unit<"ft(us)", mag_ratio<1'200, 3'937> * si::metre> {} us_survey_foot;
inline constexpr struct link : named_unit<"li", mag_ratio<33, 50> * us_survey_foot> {} link;
inline constexpr struct rod : named_unit<"rd", mag<25> * link> {} rod;
inline constexpr struct chain : named_unit<"ch", mag<4> * rod> {} chain;
inline constexpr struct furlong : named_unit<"fur", mag<10> * chain> {} furlong;
inline constexpr struct us_survey_mile : named_unit<"mi(us)", mag<8> * furlong> {} us_survey_mile;
inline constexpr struct league : named_unit<"lea", mag<3> * us_survey_mile> {} league;
inline constexpr struct us_survey_foot final : named_unit<"ft(us)", mag_ratio<1'200, 3'937> * si::metre> {} us_survey_foot;
inline constexpr struct link final : named_unit<"li", mag_ratio<33, 50> * us_survey_foot> {} link;
inline constexpr struct rod final : named_unit<"rd", mag<25> * link> {} rod;
inline constexpr struct chain final : named_unit<"ch", mag<4> * rod> {} chain;
inline constexpr struct furlong final : named_unit<"fur", mag<10> * chain> {} furlong;
inline constexpr struct us_survey_mile final : named_unit<"mi(us)", mag<8> * furlong> {} us_survey_mile;
inline constexpr struct league final : named_unit<"lea", mag<3> * us_survey_mile> {} league;
// clang-format on
} // namespace survey1893
// clang-format off
// https://en.wikipedia.org/wiki/United_States_customary_units#Area
inline constexpr struct acre : named_unit<"acre", mag<10> * square(survey1893::chain)> {} acre;
inline constexpr struct section : named_unit<"section", mag<640> * acre> {} section;
inline constexpr struct acre final : named_unit<"acre", mag<10> * square(survey1893::chain)> {} acre;
inline constexpr struct section final : named_unit<"section", mag<640> * acre> {} section;
// https://en.wikipedia.org/wiki/United_States_customary_units#Fluid_volume
inline constexpr struct gallon : named_unit<"gal", mag<231> * cubic(inch)> {} gallon;
inline constexpr struct pottle : named_unit<"pot", mag_ratio<1, 2> * gallon> {} pottle;
inline constexpr struct quart : named_unit<"qt", mag_ratio<1, 2> * pottle> {} quart;
inline constexpr struct pint : named_unit<"pt", mag_ratio<1, 2> * quart> {} pint;
inline constexpr struct cup : named_unit<"c", mag_ratio<1, 2> * pint> {} cup;
inline constexpr struct gill : named_unit<"gi", mag_ratio<1, 2> * cup> {} gill;
inline constexpr struct fluid_ounce : named_unit<"fl oz", mag_ratio<1, 4> * gill> {} fluid_ounce;
inline constexpr struct tablespoon : named_unit<"tbsp", mag_ratio<1, 2> * fluid_ounce> {} tablespoon;
inline constexpr struct shot : named_unit<"jig", mag<3> * tablespoon> {} shot;
inline constexpr struct teaspoon : named_unit<"tsp", mag_ratio<1, 3> * tablespoon> {} teaspoon;
inline constexpr struct minim : named_unit<"min", mag_ratio<1, 80> * teaspoon> {} minim;
inline constexpr struct fluid_dram : named_unit<"fl dr", mag<60> * minim> {} fluid_dram;
inline constexpr struct barrel : named_unit<"bbl", mag_ratio<315, 10> * gallon> {} barrel;
inline constexpr struct oil_barrel : named_unit<"bbl", mag_ratio<4, 3> * barrel> {} oil_barrel;
inline constexpr struct hogshead : decltype(mag<63> * gallon) {} hogshead;
inline constexpr struct gallon final : named_unit<"gal", mag<231> * cubic(inch)> {} gallon;
inline constexpr struct pottle final : named_unit<"pot", mag_ratio<1, 2> * gallon> {} pottle;
inline constexpr struct quart final : named_unit<"qt", mag_ratio<1, 2> * pottle> {} quart;
inline constexpr struct pint final : named_unit<"pt", mag_ratio<1, 2> * quart> {} pint;
inline constexpr struct cup final : named_unit<"c", mag_ratio<1, 2> * pint> {} cup;
inline constexpr struct gill final : named_unit<"gi", mag_ratio<1, 2> * cup> {} gill;
inline constexpr struct fluid_ounce final : named_unit<"fl oz", mag_ratio<1, 4> * gill> {} fluid_ounce;
inline constexpr struct tablespoon final : named_unit<"tbsp", mag_ratio<1, 2> * fluid_ounce> {} tablespoon;
inline constexpr struct shot final : named_unit<"jig", mag<3> * tablespoon> {} shot;
inline constexpr struct teaspoon final : named_unit<"tsp", mag_ratio<1, 3> * tablespoon> {} teaspoon;
inline constexpr struct minim final : named_unit<"min", mag_ratio<1, 80> * teaspoon> {} minim;
inline constexpr struct fluid_dram final : named_unit<"fl dr", mag<60> * minim> {} fluid_dram;
inline constexpr struct barrel final : named_unit<"bbl", mag_ratio<315, 10> * gallon> {} barrel;
inline constexpr struct oil_barrel final : named_unit<"bbl", mag_ratio<4, 3> * barrel> {} oil_barrel;
inline constexpr struct hogshead final : named_unit<"hogshead", mag<63> * gallon> {} hogshead;
// https://en.wikipedia.org/wiki/United_States_customary_units#Dry_volume
inline constexpr struct dry_barrel : named_unit<"bbl", mag<7056> * cubic(inch)> {} dry_barrel;
inline constexpr struct bushel : named_unit<"bu", mag_ratio<3'523'907'016'688, 100'000'000'000> * si::litre> {} bushel;
inline constexpr struct peck : named_unit<"pk", mag_ratio<1, 4> * bushel> {} peck;
inline constexpr struct dry_gallon : named_unit<"gal", mag_ratio<1, 2> * peck> {} dry_gallon;
inline constexpr struct dry_quart : named_unit<"qt", mag_ratio<1, 4> * dry_gallon> {} dry_quart;
inline constexpr struct dry_pint : named_unit<"pt", mag_ratio<1, 2> * dry_quart> {} dry_pint;
inline constexpr struct dry_barrel final : named_unit<"bbl", mag<7056> * cubic(inch)> {} dry_barrel;
inline constexpr struct bushel final : named_unit<"bu", mag_ratio<3'523'907'016'688, 100'000'000'000> * si::litre> {} bushel;
inline constexpr struct peck final : named_unit<"pk", mag_ratio<1, 4> * bushel> {} peck;
inline constexpr struct dry_gallon final : named_unit<"gal", mag_ratio<1, 2> * peck> {} dry_gallon;
inline constexpr struct dry_quart final : named_unit<"qt", mag_ratio<1, 4> * dry_gallon> {} dry_quart;
inline constexpr struct dry_pint final : named_unit<"pt", mag_ratio<1, 2> * dry_quart> {} dry_pint;
// https://en.wikipedia.org/wiki/United_States_customary_units#Mass_and_Weight
// https://en.wikipedia.org/wiki/Avoirdupois_system#American_customary_system
inline constexpr struct quarter : named_unit<"qr", mag<25> * pound> {} quarter;
inline constexpr struct short_hundredweight : named_unit<"cwt", mag<100> * pound> {} short_hundredweight;
inline constexpr struct ton : named_unit<"t", mag<2'000> * pound> {} ton;
inline constexpr struct quarter final : named_unit<"qr", mag<25> * pound> {} quarter;
inline constexpr struct short_hundredweight final : named_unit<"cwt", mag<100> * pound> {} short_hundredweight;
inline constexpr struct ton final : named_unit<"t", mag<2'000> * pound> {} ton;
inline constexpr auto short_ton = ton;
inline constexpr struct pennyweight : named_unit<"dwt", mag<24> * grain> {} pennyweight;
inline constexpr struct troy_once : named_unit<"oz t", mag<20> * pennyweight> {} troy_once;
inline constexpr struct troy_pound : named_unit<"lb t", mag<12> * troy_once> {} troy_pound;
inline constexpr struct pennyweight final : named_unit<"dwt", mag<24> * grain> {} pennyweight;
inline constexpr struct troy_once final : named_unit<"oz t", mag<20> * pennyweight> {} troy_once;
inline constexpr struct troy_pound final : named_unit<"lb t", mag<12> * troy_once> {} troy_pound;
// https://en.wikipedia.org/wiki/Inch_of_mercury
inline constexpr struct inch_of_mercury : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury;
inline constexpr struct inch_of_mercury final : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury;
// https://en.wikipedia.org/wiki/United_States_customary_units#Temperature
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
inline constexpr struct degree_Fahrenheit : named_unit<symbol_text{u8"°F", "`F"}, mag_ratio<5, 9> * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
inline constexpr struct degree_Fahrenheit final : named_unit<symbol_text{u8"°F", "`F"}, mag_ratio<5, 9> * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
// clang-format on

View File

@ -1,3 +1,25 @@
// 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.
module;
#include <mp-units/bits/core_gmf.h>

View File

@ -22,6 +22,7 @@
#include <catch2/matchers/catch_matchers_templated.hpp>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <algorithm>
#ifdef MP_UNITS_MODULES
import mp_units;

View File

@ -23,6 +23,7 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_exception.hpp>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <sstream>
#include <string_view>
#ifdef MP_UNITS_MODULES

View File

@ -24,6 +24,7 @@
#include <catch2/matchers/catch_matchers.hpp>
#include <catch2/matchers/catch_matchers_exception.hpp>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <cstdint>
#include <iomanip>
#include <limits>

View File

@ -22,6 +22,7 @@
#include <catch2/catch_test_macros.hpp>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/format.h>
#include <matrix>
#include <ostream>
#ifdef MP_UNITS_MODULES

View File

@ -24,6 +24,7 @@
#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers.hpp>
#include <mp-units/ext/format.h>
#include <limits>
#include <numbers>
#ifdef MP_UNITS_MODULES
@ -37,7 +38,7 @@ using namespace mp_units;
using namespace mp_units::angular;
using namespace mp_units::angular::unit_symbols;
inline constexpr struct half_revolution : named_unit<"hrev", mag_pi * radian> {
inline constexpr struct half_revolution final : named_unit<"hrev", mag_pi * radian> {
} half_revolution;
inline constexpr auto hrev = half_revolution;

View File

@ -40,12 +40,12 @@ namespace {
using namespace mp_units;
inline constexpr struct my_origin : absolute_point_origin<my_origin, isq::length> {
inline constexpr struct my_origin final : absolute_point_origin<isq::length> {
} my_origin;
inline constexpr struct my_relative_origin : relative_point_origin<my_origin + isq::length(42 * si::metre)> {
inline constexpr struct my_relative_origin final : relative_point_origin<my_origin + isq::length(42 * si::metre)> {
} my_relative_origin;
struct dim_speed : decltype(isq::dim_length / isq::dim_time) {};
inline constexpr auto dim_speed = isq::dim_length / isq::dim_time;
// BaseDimension
static_assert(detail::BaseDimension<struct isq::dim_length>);
@ -53,7 +53,7 @@ static_assert(!detail::BaseDimension<decltype(isq::dim_length / isq::dim_time)>)
static_assert(!detail::BaseDimension<decltype(inverse(isq::dim_time))>);
static_assert(!detail::BaseDimension<decltype(pow<2>(isq::dim_length))>);
static_assert(!detail::BaseDimension<derived_dimension<struct isq::dim_length, per<struct isq::dim_time>>>);
static_assert(!detail::BaseDimension<dim_speed>);
static_assert(!detail::BaseDimension<std::remove_const_t<decltype(dim_speed)>>);
static_assert(!detail::BaseDimension<base_dimension<"L">>);
static_assert(!detail::BaseDimension<struct si::metre>);
static_assert(!detail::BaseDimension<int>);
@ -64,7 +64,7 @@ static_assert(detail::DerivedDimension<decltype(inverse(isq::dim_time))>);
static_assert(detail::DerivedDimension<decltype(pow<2>(isq::dim_length))>);
static_assert(detail::DerivedDimension<derived_dimension<struct isq::dim_length, per<struct isq::dim_time>>>);
static_assert(detail::DerivedDimension<struct dimension_one>);
static_assert(!detail::DerivedDimension<dim_speed>);
static_assert(detail::DerivedDimension<std::remove_const_t<decltype(dim_speed)>>);
static_assert(!detail::DerivedDimension<struct isq::dim_length>);
static_assert(!detail::DerivedDimension<struct si::metre>);
static_assert(!detail::DerivedDimension<int>);
@ -76,7 +76,7 @@ static_assert(Dimension<decltype(inverse(isq::dim_time))>);
static_assert(Dimension<decltype(pow<2>(isq::dim_length))>);
static_assert(Dimension<derived_dimension<struct isq::dim_length, per<struct isq::dim_time>>>);
static_assert(Dimension<struct dimension_one>);
static_assert(!Dimension<dim_speed>);
static_assert(Dimension<std::remove_const_t<decltype(dim_speed)>>);
static_assert(!Dimension<base_dimension<"L">>);
static_assert(!Dimension<struct si::metre>);
static_assert(!Dimension<int>);
@ -85,7 +85,7 @@ static_assert(!Dimension<int>);
// TODO add tests
// QuantitySpec
struct speed : decltype(isq::length / isq::time) {}; // this is not recommended
inline constexpr auto speed = isq::length / isq::time;
static_assert(QuantitySpec<struct isq::length>);
static_assert(QuantitySpec<struct isq::radius>);
@ -94,7 +94,7 @@ static_assert(QuantitySpec<decltype(kind_of<isq::length>)>);
static_assert(QuantitySpec<decltype(isq::length / isq::time)>);
static_assert(QuantitySpec<decltype(pow<2>(isq::length))>);
static_assert(QuantitySpec<struct dimensionless>);
static_assert(!QuantitySpec<speed>);
static_assert(QuantitySpec<std::remove_const_t<decltype(speed)>>);
static_assert(!QuantitySpec<struct isq::dim_length>);
static_assert(!QuantitySpec<int>);
@ -106,21 +106,21 @@ static_assert(!detail::NamedQuantitySpec<std::remove_const_t<decltype(kind_of<is
static_assert(!detail::NamedQuantitySpec<decltype(isq::length / isq::time)>);
static_assert(!detail::NamedQuantitySpec<decltype(pow<2>(isq::length))>);
static_assert(detail::NamedQuantitySpec<struct dimensionless>);
static_assert(!detail::NamedQuantitySpec<speed>);
static_assert(!detail::NamedQuantitySpec<std::remove_const_t<decltype(speed)>>);
static_assert(!detail::NamedQuantitySpec<struct isq::dim_length>);
static_assert(!detail::NamedQuantitySpec<int>);
// IntermediateDerivedQuantitySpec
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::length>);
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::radius>);
static_assert(!detail::IntermediateDerivedQuantitySpec<decltype(kind_of<isq::length>)>);
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::speed>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(isq::length / isq::time)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(pow<2>(isq::length))>);
static_assert(!detail::IntermediateDerivedQuantitySpec<struct dimensionless>);
static_assert(!detail::IntermediateDerivedQuantitySpec<speed>);
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::dim_length>);
static_assert(!detail::IntermediateDerivedQuantitySpec<int>);
// DerivedQuantitySpec
static_assert(!detail::DerivedQuantitySpec<struct isq::length>);
static_assert(!detail::DerivedQuantitySpec<struct isq::radius>);
static_assert(!detail::DerivedQuantitySpec<decltype(kind_of<isq::length>)>);
static_assert(!detail::DerivedQuantitySpec<struct isq::speed>);
static_assert(detail::DerivedQuantitySpec<decltype(isq::length / isq::time)>);
static_assert(detail::DerivedQuantitySpec<decltype(pow<2>(isq::length))>);
static_assert(!detail::DerivedQuantitySpec<struct dimensionless>);
static_assert(detail::DerivedQuantitySpec<std::remove_const_t<decltype(speed)>>);
static_assert(!detail::DerivedQuantitySpec<struct isq::dim_length>);
static_assert(!detail::DerivedQuantitySpec<int>);
// QuantityKindSpec
static_assert(!detail::QuantityKindSpec<struct isq::length>);
@ -130,7 +130,7 @@ static_assert(!detail::QuantityKindSpec<struct isq::speed>);
static_assert(!detail::QuantityKindSpec<decltype(isq::length / isq::time)>);
static_assert(!detail::QuantityKindSpec<decltype(pow<2>(isq::length))>);
static_assert(!detail::QuantityKindSpec<struct dimensionless>);
static_assert(!detail::QuantityKindSpec<speed>);
static_assert(!detail::QuantityKindSpec<std::remove_const_t<decltype(speed)>>);
static_assert(!detail::QuantityKindSpec<struct isq::dim_length>);
static_assert(!detail::QuantityKindSpec<int>);
@ -138,10 +138,8 @@ static_assert(!detail::QuantityKindSpec<int>);
// TODO add tests
// Unit
struct metre_per_second : decltype(si::metre / si::second) {};
static_assert(Unit<struct si::metre>);
static_assert(Unit<struct si::kilogram>);
static_assert(Unit<decltype(si::kilogram)>);
static_assert(Unit<decltype(si::kilo<si::gram>)>);
static_assert(Unit<struct natural::electronvolt>);
static_assert(Unit<decltype(si::metre / si::second)>);
@ -151,13 +149,12 @@ static_assert(Unit<decltype(square(si::metre))>);
static_assert(Unit<decltype(pow<2>(si::metre))>);
static_assert(Unit<struct si::standard_gravity>);
static_assert(Unit<scaled_unit<mag<10>, struct si::second>>);
static_assert(Unit<metre_per_second>);
static_assert(Unit<derived_unit<struct si::metre, per<struct si::second>>>);
static_assert(Unit<struct one>);
static_assert(!Unit<named_unit<"?", isq::length>>);
static_assert(!Unit<named_unit<"?", kind_of<isq::length>>>);
static_assert(!Unit<named_unit<"?">>);
static_assert(!Unit<named_unit<"?", si::metre / si::second>>);
static_assert(!Unit<named_unit<"?", si::metre, isq::length>>);
static_assert(!Unit<named_unit<"?", si::metre, kind_of<isq::length>>>);
static_assert(!Unit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!Unit<struct isq::dim_length>);
static_assert(!Unit<int>);
@ -168,7 +165,7 @@ static_assert(!Unit<std::chrono::seconds>);
// NamedUnit
static_assert(detail::NamedUnit<struct si::metre>);
static_assert(detail::NamedUnit<struct natural::electronvolt>);
static_assert(!detail::NamedUnit<struct si::kilogram>);
static_assert(!detail::NamedUnit<decltype(si::kilogram)>);
static_assert(!detail::NamedUnit<decltype(si::kilo<si::gram>)>);
static_assert(!detail::NamedUnit<decltype(si::metre / si::second)>);
static_assert(!detail::NamedUnit<decltype(inverse(si::second))>);
@ -177,13 +174,12 @@ static_assert(!detail::NamedUnit<decltype(square(si::metre))>);
static_assert(!detail::NamedUnit<decltype(pow<2>(si::metre))>);
static_assert(detail::NamedUnit<struct si::standard_gravity>);
static_assert(!detail::NamedUnit<scaled_unit<mag<10>, struct si::second>>);
static_assert(!detail::NamedUnit<metre_per_second>);
static_assert(!detail::NamedUnit<derived_unit<struct si::metre, per<struct si::second>>>);
static_assert(!detail::NamedUnit<struct one>);
static_assert(!detail::NamedUnit<named_unit<"?", isq::length>>);
static_assert(!detail::NamedUnit<named_unit<"?", kind_of<isq::length>>>);
static_assert(!detail::NamedUnit<named_unit<"?">>);
static_assert(!detail::NamedUnit<named_unit<"?", si::metre / si::second>>);
static_assert(!detail::NamedUnit<named_unit<"?", si::metre, isq::length>>);
static_assert(!detail::NamedUnit<named_unit<"?", si::metre, kind_of<isq::length>>>);
static_assert(!detail::NamedUnit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!detail::NamedUnit<struct isq::dim_length>);
static_assert(!detail::NamedUnit<int>);
@ -194,7 +190,7 @@ static_assert(!detail::NamedUnit<std::chrono::seconds>);
// PrefixableUnit
static_assert(PrefixableUnit<struct si::metre>);
static_assert(PrefixableUnit<struct natural::electronvolt>);
static_assert(!PrefixableUnit<struct si::kilogram>);
static_assert(!PrefixableUnit<decltype(si::kilogram)>);
static_assert(!PrefixableUnit<decltype(si::kilo<si::gram>)>);
static_assert(!PrefixableUnit<decltype(si::metre / si::second)>);
static_assert(!PrefixableUnit<decltype(inverse(si::second))>);
@ -203,13 +199,12 @@ static_assert(!PrefixableUnit<decltype(square(si::metre))>);
static_assert(!PrefixableUnit<decltype(pow<2>(si::metre))>);
static_assert(PrefixableUnit<struct si::standard_gravity>);
static_assert(!PrefixableUnit<scaled_unit<mag<10>, struct si::second>>);
static_assert(!PrefixableUnit<metre_per_second>);
static_assert(!PrefixableUnit<derived_unit<struct si::metre, per<struct si::second>>>);
static_assert(!PrefixableUnit<struct one>);
static_assert(!PrefixableUnit<named_unit<"?", isq::length>>);
static_assert(!PrefixableUnit<named_unit<"?", kind_of<isq::length>>>);
static_assert(!PrefixableUnit<named_unit<"?">>);
static_assert(!PrefixableUnit<named_unit<"?", si::metre / si::second>>);
static_assert(!PrefixableUnit<named_unit<"?", si::metre, isq::length>>);
static_assert(!PrefixableUnit<named_unit<"?", si::metre, kind_of<isq::length>>>);
static_assert(!PrefixableUnit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!PrefixableUnit<struct isq::dim_length>);
static_assert(!PrefixableUnit<int>);
@ -220,7 +215,7 @@ static_assert(!PrefixableUnit<std::chrono::seconds>);
// AssociatedUnit
static_assert(AssociatedUnit<struct si::metre>);
static_assert(!AssociatedUnit<struct natural::electronvolt>);
static_assert(AssociatedUnit<struct si::kilogram>);
static_assert(AssociatedUnit<decltype(si::kilogram)>);
static_assert(AssociatedUnit<decltype(si::kilo<si::gram>)>);
static_assert(AssociatedUnit<decltype(si::metre / si::second)>);
static_assert(AssociatedUnit<decltype(inverse(si::second))>);
@ -229,13 +224,12 @@ static_assert(AssociatedUnit<decltype(square(si::metre))>);
static_assert(AssociatedUnit<decltype(pow<2>(si::metre))>);
static_assert(AssociatedUnit<struct si::standard_gravity>);
static_assert(AssociatedUnit<scaled_unit<mag<10>, struct si::second>>);
static_assert(AssociatedUnit<metre_per_second>);
static_assert(AssociatedUnit<derived_unit<struct si::metre, per<struct si::second>>>);
static_assert(AssociatedUnit<struct one>);
static_assert(!AssociatedUnit<named_unit<"?", isq::length>>);
static_assert(!AssociatedUnit<named_unit<"?", kind_of<isq::length>>>);
static_assert(!AssociatedUnit<named_unit<"?">>);
static_assert(!AssociatedUnit<named_unit<"?", si::metre / si::second>>);
static_assert(!AssociatedUnit<named_unit<"?", si::metre, isq::length>>);
static_assert(!AssociatedUnit<named_unit<"?", si::metre, kind_of<isq::length>>>);
static_assert(!AssociatedUnit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!AssociatedUnit<struct isq::dim_length>);
static_assert(!AssociatedUnit<int>);
@ -246,7 +240,7 @@ static_assert(!AssociatedUnit<std::chrono::seconds>);
// UnitOf
static_assert(UnitOf<struct si::metre, isq::length>);
static_assert(UnitOf<struct si::metre, isq::radius>);
static_assert(UnitOf<struct si::kilogram, isq::mass>);
static_assert(UnitOf<decltype(si::kilogram), isq::mass>);
static_assert(UnitOf<struct si::hertz, isq::frequency>);
static_assert(UnitOf<struct si::hertz, inverse(isq::time)>);
static_assert(UnitOf<struct one, dimensionless>);
@ -366,7 +360,7 @@ static_assert(QuantityPoint<quantity_point<isq::length[si::metre], my_relative_o
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_origin>>);
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_relative_origin>>);
static_assert(!QuantityPoint<decltype(isq::length[si::metre])>);
static_assert(!QuantityPoint<absolute_point_origin<struct my_origin, isq::length>>);
static_assert(!QuantityPoint<absolute_point_origin<isq::length>>);
static_assert(!QuantityPoint<struct my_origin>);
static_assert(!QuantityPoint<struct my_relative_origin>);
#if MP_UNITS_HOSTED
@ -400,7 +394,7 @@ static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative
// PointOrigin
static_assert(PointOrigin<struct my_origin>);
static_assert(PointOrigin<struct my_relative_origin>);
static_assert(!PointOrigin<absolute_point_origin<struct my_origin, isq::length>>);
static_assert(!PointOrigin<absolute_point_origin<isq::length>>);
static_assert(!PointOrigin<relative_point_origin<my_origin + 42 * si::metre>>);
static_assert(!PointOrigin<quantity_point<si::metre, my_origin>>);
static_assert(!PointOrigin<quantity_point<isq::length[si::metre], my_origin>>);

View File

@ -32,15 +32,15 @@ using namespace mp_units;
using dimension_one_ = struct dimension_one;
// clang-format off
inline constexpr struct length_ : base_dimension<"L"> {} length;
inline constexpr struct mass_ : base_dimension<"M"> {} mass;
inline constexpr struct time_ : base_dimension<"T"> {} time;
inline constexpr struct length_ final : base_dimension<"L"> {} length;
inline constexpr struct mass_ final : base_dimension<"M"> {} mass;
inline constexpr struct time_ final : base_dimension<"T"> {} time;
inline constexpr struct my_length1_ : decltype(length) {} my_length1;
inline constexpr struct my_length2_ : decltype(length) {} my_length2;
inline constexpr auto my_length1 = length;
inline constexpr auto my_length2 = length;
QUANTITY_SPEC_(q_time, time);
inline constexpr struct second_ : named_unit<"s", kind_of<q_time>> {} second;
inline constexpr struct second_ final : named_unit<"s", kind_of<q_time>> {} second;
inline constexpr auto frequency = inverse(time);
inline constexpr auto action = inverse(time);

View File

@ -46,40 +46,38 @@ using namespace std::chrono_literals;
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
#endif
inline constexpr struct zeroth_length : absolute_point_origin<zeroth_length, isq::length> {
inline constexpr struct zeroth_length final : absolute_point_origin<isq::length> {
} zeroth_length;
inline constexpr struct mean_sea_level : absolute_point_origin<mean_sea_level, isq::height> {
inline constexpr struct mean_sea_level final : absolute_point_origin<isq::height> {
} mean_sea_level;
inline constexpr struct my_mean_sea_level : decltype(mean_sea_level) {
} my_mean_sea_level;
inline constexpr auto my_mean_sea_level = mean_sea_level;
inline constexpr struct same_mean_sea_level : relative_point_origin<mean_sea_level + 0 * isq::height[m]> {
inline constexpr struct same_mean_sea_level final : relative_point_origin<mean_sea_level + 0 * isq::height[m]> {
} same_mean_sea_level;
inline constexpr struct ground_level : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
inline constexpr struct ground_level final : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
} ground_level;
inline constexpr struct my_ground_level : decltype(ground_level) {
} my_ground_level;
inline constexpr auto my_ground_level = ground_level;
inline constexpr struct same_ground_level1 : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
inline constexpr struct same_ground_level1 final : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
} same_ground_level1;
inline constexpr struct same_ground_level2 : relative_point_origin<my_mean_sea_level + 42 * isq::height[m]> {
inline constexpr struct same_ground_level2 final : relative_point_origin<my_mean_sea_level + 42 * isq::height[m]> {
} same_ground_level2;
inline constexpr struct tower_peak : relative_point_origin<ground_level + 42 * isq::height[m]> {
inline constexpr struct tower_peak final : relative_point_origin<ground_level + 42 * isq::height[m]> {
} tower_peak;
inline constexpr struct other_ground_level : relative_point_origin<mean_sea_level + 123 * isq::height[m]> {
inline constexpr struct other_ground_level final : relative_point_origin<mean_sea_level + 123 * isq::height[m]> {
} other_ground_level;
inline constexpr struct other_absolute_level : absolute_point_origin<other_absolute_level, isq::height> {
inline constexpr struct other_absolute_level final : absolute_point_origin<isq::height> {
} other_absolute_level;
inline constexpr struct zero : absolute_point_origin<zero, dimensionless> {
inline constexpr struct zero final : absolute_point_origin<dimensionless> {
} zero;
QUANTITY_SPEC(special_height, isq::height);
@ -107,12 +105,12 @@ static_assert(my_mean_sea_level != other_absolute_level);
static_assert(ground_level != other_ground_level);
template<auto QS>
struct absolute_po_ : absolute_point_origin<absolute_po_<QS>, QS> {};
struct absolute_po_ final : absolute_point_origin<QS> {};
template<auto QS>
inline constexpr absolute_po_<QS> absolute_po;
template<auto QP>
struct relative_po_ : relative_point_origin<QP> {};
struct relative_po_ final : relative_point_origin<QP> {};
template<auto QP>
inline constexpr relative_po_<QP> relative_po;
@ -120,7 +118,7 @@ static_assert(relative_po<absolute_po<isq::length> + isq::height(42 * m)>.quanti
static_assert(relative_po<absolute_po<kind_of<isq::length>> + isq::height(42 * m)>.quantity_spec == isq::height);
static_assert(relative_po<absolute_po<isq::height> + 42 * m>.quantity_spec == isq::height);
inline constexpr struct my_kelvin : named_unit<"my_K", mag<10> * si::kelvin> {
inline constexpr struct my_kelvin final : named_unit<"my_K", mag<10> * si::kelvin> {
} my_kelvin;
static_assert(default_point_origin(si::kelvin) == si::absolute_zero);
@ -311,7 +309,7 @@ static_assert(quantity_point<si::degree_Celsius, si::ice_point>::dimension == is
static_assert(quantity_point<si::degree_Celsius, si::ice_point>::unit == si::degree_Celsius);
static_assert(is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::point_origin, struct si::ice_point>);
static_assert(
is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::absolute_point_origin, struct si::zeroth_kelvin>);
is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::absolute_point_origin, struct si::absolute_zero>);
static_assert(quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::reference ==
isq::Celsius_temperature[si::degree_Celsius]);
@ -324,7 +322,7 @@ static_assert(is_of_type<quantity_point<isq::Celsius_temperature[si::degree_Cels
struct si::ice_point>);
static_assert(
is_of_type<quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::absolute_point_origin,
struct si::zeroth_kelvin>);
struct si::absolute_zero>);
//////////////////
@ -892,10 +890,10 @@ static_assert(quantity_point{isq::height(123 * m)}.unit == si::metre);
static_assert(quantity_point{isq::height(123 * m)}.quantity_spec == isq::height);
static_assert(std::is_same_v<decltype(quantity_point{20 * deg_C})::rep, int>);
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{20 * deg_C}.point_origin)>,
struct si::zeroth_degree_Celsius>);
static_assert(
std::is_same_v<std::remove_const_t<decltype(quantity_point{20 * deg_C}.point_origin)>, struct si::ice_point>);
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{20 * deg_C}.absolute_point_origin)>,
struct si::zeroth_kelvin>);
struct si::absolute_zero>);
static_assert(quantity_point{20 * deg_C}.unit == si::degree_Celsius);
static_assert(quantity_point{20 * deg_C}.quantity_spec == kind_of<isq::thermodynamic_temperature>);
@ -1493,7 +1491,7 @@ static_assert(ground_level - other_ground_level == -81 * m);
static_assert(other_ground_level - tower_peak == 39 * m);
static_assert(tower_peak - other_ground_level == -39 * m);
inline constexpr struct zero_m_per_s : absolute_point_origin<zero_m_per_s, kind_of<isq::speed>> {
inline constexpr struct zero_m_per_s final : absolute_point_origin<kind_of<isq::speed>> {
} zero_m_per_s;
// commutativity and associativity
@ -1581,7 +1579,7 @@ static_assert(
is_of_type<quantity_point{10 * isq::height[m] / (2 * isq::time[s])} + (10 * isq::height[m] / (2 * isq::time[s])),
quantity_point<(isq::height / isq::time)[m / s], zeroth_point_origin<isq::height / isq::time>, int>>);
inline constexpr struct zero_Hz : absolute_point_origin<zero_Hz, kind_of<isq::frequency>> {
inline constexpr struct zero_Hz final : absolute_point_origin<kind_of<isq::frequency>> {
} zero_Hz;
static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_from(zero_Hz) ==
@ -1665,7 +1663,7 @@ consteval bool invalid_subtraction(Ts... ts)
return !requires { (... - ts); };
}
inline constexpr struct zero_Bq : absolute_point_origin<zero_Bq, kind_of<isq::activity>> {
inline constexpr struct zero_Bq final : absolute_point_origin<kind_of<isq::activity>> {
} zero_Bq;
static_assert(invalid_addition(zero_Bq + 5 * isq::activity[Bq], 5 * isq::frequency[Hz]));

View File

@ -33,16 +33,16 @@ using dimensionless_ = struct dimensionless;
using dim_one_ = struct dimension_one;
// clang-format off
inline constexpr struct dim_length_ : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass_ : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time_ : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_length_ final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass_ final : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time_ final : base_dimension<"T"> {} dim_time;
// quantities specification
QUANTITY_SPEC_(length, dim_length);
QUANTITY_SPEC_(mass, dim_mass);
QUANTITY_SPEC_(time, dim_time);
inline constexpr struct second_ : named_unit<"s", kind_of<time>> {} second;
inline constexpr struct second_ final : named_unit<"s", kind_of<time>> {} second;
QUANTITY_SPEC_(height, length);
QUANTITY_SPEC_(width, length);
@ -88,98 +88,98 @@ QUANTITY_SPEC_(kinetic_energy, mechanical_energy, mass* pow<2>(speed));
// concepts verification
static_assert(QuantitySpec<length_>);
static_assert(detail::NamedQuantitySpec<length_>);
static_assert(!detail::IntermediateDerivedQuantitySpec<length_>);
static_assert(!detail::DerivedQuantitySpec<length_>);
static_assert(!detail::QuantityKindSpec<length_>);
static_assert(QuantitySpec<frequency_>);
static_assert(detail::NamedQuantitySpec<frequency_>);
static_assert(!detail::IntermediateDerivedQuantitySpec<frequency_>);
static_assert(!detail::DerivedQuantitySpec<frequency_>);
static_assert(!detail::QuantityKindSpec<frequency_>);
static_assert(QuantitySpec<decltype(inverse(time))>);
static_assert(!detail::NamedQuantitySpec<decltype(inverse(time))>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(inverse(time))>);
static_assert(detail::DerivedQuantitySpec<decltype(inverse(time))>);
static_assert(!detail::QuantityKindSpec<decltype(inverse(time))>);
static_assert(QuantitySpec<dimensionless_>);
static_assert(detail::NamedQuantitySpec<dimensionless_>);
static_assert(!detail::IntermediateDerivedQuantitySpec<dimensionless_>);
static_assert(!detail::DerivedQuantitySpec<dimensionless_>);
static_assert(!detail::QuantityKindSpec<dimensionless_>);
static_assert(QuantitySpec<kind_of_<length_>>);
static_assert(!detail::NamedQuantitySpec<kind_of_<length_>>);
static_assert(!detail::IntermediateDerivedQuantitySpec<kind_of_<length_>>);
static_assert(!detail::DerivedQuantitySpec<kind_of_<length_>>);
static_assert(detail::QuantityKindSpec<kind_of_<length_>>);
static_assert(QuantitySpec<frequency_>);
static_assert(detail::NamedQuantitySpec<frequency_>);
static_assert(!detail::IntermediateDerivedQuantitySpec<frequency_>);
static_assert(!detail::DerivedQuantitySpec<frequency_>);
static_assert(!detail::QuantityKindSpec<frequency_>);
static_assert(QuantitySpec<decltype(inverse(time))>);
static_assert(!detail::NamedQuantitySpec<decltype(inverse(time))>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(inverse(time))>);
static_assert(detail::DerivedQuantitySpec<decltype(inverse(time))>);
static_assert(!detail::QuantityKindSpec<decltype(inverse(time))>);
static_assert(QuantitySpec<kind_of_<decltype(length / time)>>);
static_assert(!detail::NamedQuantitySpec<kind_of_<decltype(length / time)>>);
static_assert(detail::IntermediateDerivedQuantitySpec<kind_of_<decltype(length / time)>>);
static_assert(detail::DerivedQuantitySpec<kind_of_<decltype(length / time)>>);
static_assert(detail::QuantityKindSpec<kind_of_<decltype(length / time)>>);
static_assert(QuantitySpec<decltype(kind_of<length> / kind_of<time>)>);
static_assert(!detail::NamedQuantitySpec<decltype(kind_of<length> / kind_of<time>)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(kind_of<length> / kind_of<time>)>);
static_assert(detail::DerivedQuantitySpec<decltype(kind_of<length> / kind_of<time>)>);
static_assert(detail::QuantityKindSpec<decltype(kind_of<length> / kind_of<time>)>);
static_assert(QuantitySpec<decltype(kind_of<length> * kind_of<time>)>);
static_assert(!detail::NamedQuantitySpec<decltype(kind_of<length> * kind_of<time>)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(kind_of<length> * kind_of<time>)>);
static_assert(detail::DerivedQuantitySpec<decltype(kind_of<length> * kind_of<time>)>);
static_assert(detail::QuantityKindSpec<decltype(kind_of<length> * kind_of<time>)>);
// dimensionless
static_assert(QuantitySpec<dimensionless_>);
static_assert(detail::NamedQuantitySpec<dimensionless_>);
static_assert(!detail::IntermediateDerivedQuantitySpec<dimensionless_>);
static_assert(!detail::DerivedQuantitySpec<dimensionless_>);
static_assert(!detail::QuantityKindSpec<dimensionless_>);
static_assert(QuantitySpec<decltype(length / length)>);
static_assert(detail::NamedQuantitySpec<decltype(length / length)>);
static_assert(!detail::IntermediateDerivedQuantitySpec<decltype(length / length)>);
static_assert(!detail::DerivedQuantitySpec<decltype(length / length)>);
static_assert(!detail::QuantityKindSpec<decltype(length / length)>);
static_assert(QuantitySpec<decltype(width / length)>);
static_assert(!detail::NamedQuantitySpec<decltype(width / length)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(width / length)>);
static_assert(detail::DerivedQuantitySpec<decltype(width / length)>);
static_assert(!detail::QuantityKindSpec<decltype(width / length)>);
static_assert(QuantitySpec<decltype(kind_of<length> / kind_of<length>)>);
static_assert(!detail::NamedQuantitySpec<decltype(kind_of<length> / kind_of<length>)>);
static_assert(!detail::IntermediateDerivedQuantitySpec<decltype(kind_of<length> / kind_of<length>)>);
static_assert(!detail::DerivedQuantitySpec<decltype(kind_of<length> / kind_of<length>)>);
static_assert(detail::QuantityKindSpec<decltype(kind_of<length> / kind_of<length>)>);
static_assert(QuantitySpec<decltype(kind_of<length> / length)>);
static_assert(detail::NamedQuantitySpec<decltype(kind_of<length> / length)>);
static_assert(!detail::IntermediateDerivedQuantitySpec<decltype(kind_of<length> / length)>);
static_assert(!detail::DerivedQuantitySpec<decltype(kind_of<length> / length)>);
static_assert(!detail::QuantityKindSpec<decltype(kind_of<length> / length)>);
static_assert(QuantitySpec<decltype(length / kind_of<length>)>);
static_assert(detail::NamedQuantitySpec<decltype(length / kind_of<length>)>);
static_assert(!detail::IntermediateDerivedQuantitySpec<decltype(length / kind_of<length>)>);
static_assert(!detail::DerivedQuantitySpec<decltype(length / kind_of<length>)>);
static_assert(!detail::QuantityKindSpec<decltype(length / kind_of<length>)>);
static_assert(QuantitySpec<decltype(width / kind_of<length>)>);
static_assert(!detail::NamedQuantitySpec<decltype(width / kind_of<length>)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(width / kind_of<length>)>);
static_assert(detail::DerivedQuantitySpec<decltype(width / kind_of<length>)>);
static_assert(!detail::QuantityKindSpec<decltype(width / kind_of<length>)>);
// length
static_assert(QuantitySpec<decltype(speed * time)>);
static_assert(!detail::NamedQuantitySpec<decltype(speed * time)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(speed * time)>);
static_assert(detail::DerivedQuantitySpec<decltype(speed * time)>);
// derived QuantitySpec expression template syntax verification
static_assert(!detail::NamedQuantitySpec<decltype(speed * time)>);
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(speed * time)>);
static_assert(detail::DerivedQuantitySpec<decltype(speed * time)>);
static_assert(is_of_type<dimensionless * time, time_>);
static_assert(is_of_type<time * dimensionless, time_>);

View File

@ -35,9 +35,9 @@ using one_ = struct one;
// base dimensions
// clang-format off
inline constexpr struct dim_length_ : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass_ : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time_ : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_length_ final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass_ final : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time_ final : base_dimension<"T"> {} dim_time;
// quantities specification
QUANTITY_SPEC_(length, dim_length);
@ -60,16 +60,16 @@ QUANTITY_SPEC_(power, force* speed);
QUANTITY_SPEC_(storage_capacity, dimensionless, is_kind);
// base units
inline constexpr struct second_ : named_unit<"s", kind_of<time>> {} second;
inline constexpr struct metre_ : named_unit<"m", kind_of<length>> {} metre;
inline constexpr struct gram_ : named_unit<"g", kind_of<mass>> {} gram;
inline constexpr struct kilogram_ : decltype(si::kilo<gram>) {} kilogram;
inline constexpr struct second_ final : named_unit<"s", kind_of<time>> {} second;
inline constexpr struct metre_ final : named_unit<"m", kind_of<length>> {} metre;
inline constexpr struct gram_ final : named_unit<"g", kind_of<mass>> {} gram;
inline constexpr auto kilogram = si::kilo<gram>;
namespace nu {
// hypothetical natural system of units for c=1
inline constexpr struct second_ : named_unit<"s"> {} second;
inline constexpr struct minute_ : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct second_ final : named_unit<"s"> {} second;
inline constexpr struct minute_ final : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct time : system_reference<time_{}, second> {} time;
inline constexpr struct length : system_reference<length_{}, second> {} length;
@ -78,19 +78,19 @@ inline constexpr struct speed : system_reference<speed_{}, second / second> {} s
}
// derived named units
inline constexpr struct radian_ : named_unit<"rad", metre / metre, kind_of<angular_measure>> {} radian;
inline constexpr struct steradian_ : named_unit<"sr", square(metre) / square(metre), kind_of<solid_angular_measure>> {} steradian;
inline constexpr struct hertz_ : named_unit<"Hz", inverse(second), kind_of<frequency>> {} hertz;
inline constexpr struct becquerel_ : named_unit<"Bq", inverse(second), kind_of<activity>> {} becquerel;
inline constexpr struct newton_ : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct joule_ : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt_ : named_unit<"W", joule / second> {} watt;
inline constexpr struct radian_ final : named_unit<"rad", metre / metre, kind_of<angular_measure>> {} radian;
inline constexpr struct steradian_ final : named_unit<"sr", square(metre) / square(metre), kind_of<solid_angular_measure>> {} steradian;
inline constexpr struct hertz_ final : named_unit<"Hz", inverse(second), kind_of<frequency>> {} hertz;
inline constexpr struct becquerel_ final : named_unit<"Bq", inverse(second), kind_of<activity>> {} becquerel;
inline constexpr struct newton_ final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct joule_ final : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt_ final : named_unit<"W", joule / second> {} watt;
inline constexpr struct minute_ : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct hour_ : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct kilometre_ : decltype(si::kilo<metre>) {} kilometre;
inline constexpr struct minute_ final : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct hour_ final : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr auto kilometre = si::kilo<metre>;
inline constexpr struct bit_ : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
inline constexpr struct bit_ final : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
// clang-format on
@ -189,27 +189,27 @@ static_assert(
constexpr auto m_per_s = speed[metre / second];
static_assert(is_of_type<2 * m_per_s, quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
static_assert(
is_of_type<
120 * length[kilometre] / (2 * time[hour]),
quantity<reference<derived_quantity_spec<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, int>>);
static_assert(is_of_type<120 * length[kilometre] / (2 * time[hour]),
quantity<reference<derived_quantity_spec<length_, per<time_>>,
derived_unit<std::remove_const_t<decltype(si::kilo<metre>)>, per<hour_>>>{},
int>>);
static_assert(120 * length[kilometre] / (2 * time[hour]) == 60 * speed[kilometre / hour]);
static_assert(
is_of_type<
[] {
const auto distance = 120;
const auto duration = 2;
return distance * length[kilometre] / (duration * time[hour]);
}(),
quantity<reference<derived_quantity_spec<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, int>>);
static_assert(
is_of_type<std::int64_t{120} * length[kilometre] / (2 * time[hour]),
quantity<reference<derived_quantity_spec<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{},
std::int64_t>>);
static_assert(
is_of_type<120.L * length[kilometre] / (2 * time[hour]),
quantity<reference<derived_quantity_spec<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{},
long double>>);
static_assert(is_of_type<[] {
const auto distance = 120;
const auto duration = 2;
return distance * length[kilometre] / (duration * time[hour]);
}(),
quantity<reference<derived_quantity_spec<length_, per<time_>>,
derived_unit<std::remove_const_t<decltype(si::kilo<metre>)>, per<hour_>>>{},
int>>);
static_assert(is_of_type<std::int64_t{120} * length[kilometre] / (2 * time[hour]),
quantity<reference<derived_quantity_spec<length_, per<time_>>,
derived_unit<std::remove_const_t<decltype(si::kilo<metre>)>, per<hour_>>>{},
std::int64_t>>);
static_assert(is_of_type<120.L * length[kilometre] / (2 * time[hour]),
quantity<reference<derived_quantity_spec<length_, per<time_>>,
derived_unit<std::remove_const_t<decltype(si::kilo<metre>)>, per<hour_>>>{},
long double>>);
static_assert(is_of_type<1. / 4 * area[square(metre)], decltype(1. * area[square(metre)] / 4)>);
static_assert(1. / 4 * area[square(metre)] == 1. * area[square(metre)] / 4);
@ -226,7 +226,9 @@ static_assert(is_of_type<42 * nu::length[nu::second] / (42 * nu::time[nu::second
static_assert(is_of_type<42 * nu::speed[nu::second / nu::second], quantity<reference<speed_, one_>{}, int>>);
static_assert(is_of_type<42 * nu::speed[one], quantity<reference<speed_, one_>{}, int>>);
static_assert(is_of_type<42 * mass[kilogram] * (1 * nu::length[nu::second]) / (1 * nu::time[nu::second]),
quantity<reference<derived_quantity_spec<length_, mass_, per<time_>>, kilogram_>{}, int>>);
quantity<reference<derived_quantity_spec<length_, mass_, per<time_>>,
std::remove_const_t<decltype(si::kilo<gram>)>>{},
int>>);
template<auto dim, auto unit>
concept invalid_nu_unit = !requires { dim[unit]; };

Some files were not shown because too many files have changed in this diff Show More