diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a5ae64e..cc38d895 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,11 +5,12 @@
### 2.2.0 WIP { 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 `` 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 May 16, 2024 { id="2.1.1" }
diff --git a/conanfile.py b/conanfile.py
index 0d2cb39b..abdebc30 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -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"]
diff --git a/docs/blog/posts/2.2.0-released.md b/docs/blog/posts/2.2.0-released.md
index 936840a1..6dd7bd46 100644
--- a/docs/blog/posts/2.2.0-released.md
+++ b/docs/blog/posts/2.2.0-released.md
@@ -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;
+ constexpr struct zero final : absolute_point_origin {} 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` 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 {} ohm;
+ inline constexpr struct ohm final : named_unit {} 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 {} length;
+
+ inline constexpr struct absolute_zero final : absolute_point_origin {} absolute_zero;
+ inline constexpr auto zeroth_kelvin = absolute_zero;
+ inline constexpr struct kelvin final : named_unit<"K", kind_of, zeroth_kelvin> {} kelvin;
+
+ inline constexpr struct ice_point final : relative_point_origin}> {} ice_point;
+ inline constexpr auto zeroth_degree_Celsius = ice_point;
+ inline constexpr struct degree_Celsius final : named_unit {} degree_Celsius;
+ ```
+
+=== "Before"
+
+ ```cpp
+ inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
+ inline constexpr struct length : quantity_spec {} length;
+
+ inline constexpr struct absolute_zero : absolute_point_origin {} absolute_zero;
+ inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
+ inline constexpr struct kelvin : named_unit<"K", kind_of, zeroth_kelvin> {} kelvin;
+
+ inline constexpr struct ice_point : relative_point_origin}> {} ice_point;
+ inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
+ inline constexpr struct degree_Celsius : named_unit {} 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"
diff --git a/docs/getting_started/installation_and_usage.md b/docs/getting_started/installation_and_usage.md
index 175bf545..d1c4a079 100644
--- a/docs/getting_started/installation_and_usage.md
+++ b/docs/getting_started/installation_and_usage.md
@@ -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).
diff --git a/docs/index.md b/docs/index.md
index ea4b50d0..260316e1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -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`?"
diff --git a/docs/users_guide/examples/avg_speed.md b/docs/users_guide/examples/avg_speed.md
index 73bba732..397cafc1 100644
--- a/docs/users_guide/examples/avg_speed.md
+++ b/docs/users_guide/examples/avg_speed.md
@@ -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
diff --git a/docs/users_guide/examples/hello_units.md b/docs/users_guide/examples/hello_units.md
index c77f2287..dd69fcf4 100644
--- a/docs/users_guide/examples/hello_units.md
+++ b/docs/users_guide/examples/hello_units.md
@@ -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).
diff --git a/docs/users_guide/examples/si_constants.md b/docs/users_guide/examples/si_constants.md
index ab331bc6..05dbfbc2 100644
--- a/docs/users_guide/examples/si_constants.md
+++ b/docs/users_guide/examples/si_constants.md
@@ -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
diff --git a/docs/users_guide/framework_basics/character_of_a_quantity.md b/docs/users_guide/framework_basics/character_of_a_quantity.md
index ad366078..26b358af 100644
--- a/docs/users_guide/framework_basics/character_of_a_quantity.md
+++ b/docs/users_guide/framework_basics/character_of_a_quantity.md
@@ -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 {} position_vector;
- inline constexpr struct displacement : quantity_spec {} displacement;
+ inline constexpr struct position_vector final : quantity_spec {} position_vector;
+ inline constexpr struct displacement final : quantity_spec {} displacement;
```
=== "C++20"
```cpp
- inline constexpr struct position_vector : quantity_spec {} position_vector;
- inline constexpr struct displacement : quantity_spec {} displacement;
+ inline constexpr struct position_vector final : quantity_spec {} position_vector;
+ inline constexpr struct displacement final : quantity_spec {} displacement;
```
=== "Portable"
@@ -126,13 +126,13 @@ character override is needed):
=== "C++23"
```cpp
- inline constexpr struct velocity : quantity_spec {} velocity;
+ inline constexpr struct velocity final : quantity_spec {} velocity;
```
=== "C++20"
```cpp
- inline constexpr struct velocity : quantity_spec {} velocity;
+ inline constexpr struct velocity final : quantity_spec {} velocity;
```
=== "Portable"
diff --git a/docs/users_guide/framework_basics/concepts.md b/docs/users_guide/framework_basics/concepts.md
index 494675a6..da21dcd5 100644
--- a/docs/users_guide/framework_basics/concepts.md
+++ b/docs/users_guide/framework_basics/concepts.md
@@ -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` { #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` { #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 {} mean_sea_level;
+ inline constexpr struct mean_sea_level final : absolute_point_origin {} 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> {
using T = std::chrono::time_point;
static constexpr auto reference = si::second;
- static constexpr struct point_origin : absolute_point_origin {} point_origin{};
+ static constexpr struct point_origin final : absolute_point_origin {} point_origin{};
using rep = std::chrono::seconds::rep;
[[nodiscard]] static constexpr convert_implicitly> to_quantity(const T& qp)
diff --git a/docs/users_guide/framework_basics/design_overview.md b/docs/users_guide/framework_basics/design_overview.md
index da38cd95..04857726 100644
--- a/docs/users_guide/framework_basics/design_overview.md
+++ b/docs/users_guide/framework_basics/design_overview.md
@@ -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 {} length;
- inline constexpr struct time : quantity_spec {} time;
- inline constexpr struct speed : quantity_spec {} speed;
+ inline constexpr struct length final : quantity_spec {} length;
+ inline constexpr struct time final : quantity_spec {} time;
+ inline constexpr struct speed final : quantity_spec {} 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;
- inline constexpr struct time : quantity_spec