mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 19:04:27 +02:00
feat: 💥 unit_can_be_prefixed
removed - from now on all named units can be prefixed
Resolves #604
This commit is contained in:
@@ -117,20 +117,8 @@ and is satisfied by:
|
|||||||
|
|
||||||
### `PrefixableUnit<T>` { #PrefixableUnit }
|
### `PrefixableUnit<T>` { #PrefixableUnit }
|
||||||
|
|
||||||
`PrefixableUnit` concept is satisfied by all units derived from a `named_unit` class template for
|
`PrefixableUnit` concept is satisfied by all units derived from a `named_unit` class template.
|
||||||
which a customization point `unit_can_be_prefixed<T{}>` was not explicitly set to `false`. Such
|
Such units can be passed as an argument to a `prefixed_unit` class template.
|
||||||
units can be passed as an argument to a `prefixed_unit` class template.
|
|
||||||
|
|
||||||
??? abstract "Examples"
|
|
||||||
|
|
||||||
All units in the [SI](../../appendix/glossary.md#si) can be prefixed with SI-defined prefixes.
|
|
||||||
|
|
||||||
Some [off-system units](../../appendix/glossary.md#off-system-unit) like `non_si::day`
|
|
||||||
can't be prefixed. To enforce that, the following has to be provided:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
template<> inline constexpr bool unit_can_be_prefixed<non_si::day> = false;
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### `UnitOf<T, V>` { #UnitOf }
|
### `UnitOf<T, V>` { #UnitOf }
|
||||||
|
@@ -190,21 +190,3 @@ inline constexpr struct mag_pi final : magnitude<std::numbers::pi_v<long double>
|
|||||||
```cpp
|
```cpp
|
||||||
inline constexpr struct degree final : 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;
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! tip
|
|
||||||
|
|
||||||
The ISO 8000 and [SI](../../appendix/glossary.md#si) standards explicitly forbid using prefixes
|
|
||||||
with some units (e.g., day, minute, hour, degree Celsius). This is why the library disallows
|
|
||||||
this as well by providing specializations of the `unit_can_be_prefixed` variable template for
|
|
||||||
such units. Thanks to it trying to create a prefixed version for them will result in
|
|
||||||
a compile-time error.
|
|
||||||
|
|
||||||
However, some projects are not aware of those limitations and use prefixed version of such units
|
|
||||||
(e.g., [linux kernel uses millidegrees Celsius](https://github.com/search?q=repo%3Atorvalds%2Flinux+millidegree&type=code)).
|
|
||||||
To enable compatibility with those projects we can workaround the limitation in **mp-units**
|
|
||||||
by providing a scaled version of the unit explicitly:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
inline constexpr struct milli_degree_celsius final : named_unit<symbol_text{u8"m℃", "m`C"}, mag_ratio<1, 1000> * si::degree_Celsius> {} milli_degree_celsius;
|
|
||||||
inline constexpr auto mdeg_C = milli_degree_celsius;
|
|
||||||
```
|
|
||||||
|
@@ -62,38 +62,13 @@ template<typename T>
|
|||||||
inline constexpr bool is_derived_from_specialization_of_named_unit =
|
inline constexpr bool is_derived_from_specialization_of_named_unit =
|
||||||
requires(T* t) { to_base_specialization_of_named_unit(t); };
|
requires(T* t) { to_base_specialization_of_named_unit(t); };
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_specialization_of_named_unit = false;
|
|
||||||
|
|
||||||
template<symbol_text Symbol, auto... Args>
|
|
||||||
inline constexpr bool is_specialization_of_named_unit<named_unit<Symbol, Args...>> = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all units with special names
|
|
||||||
*
|
|
||||||
* Satisfied by all unit types derived from the specialization of `named_unit`.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept NamedUnit =
|
|
||||||
Unit<T> && detail::is_derived_from_specialization_of_named_unit<T> && (!detail::is_specialization_of_named_unit<T>);
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Prevents assignment of a prefix to specific units
|
|
||||||
*
|
|
||||||
* By default all named units allow assigning a prefix for them. There are some notable exceptions like
|
|
||||||
* `hour` or `degree_Celsius`. For those a partial specialization with the value `false` should be
|
|
||||||
* provided.
|
|
||||||
*/
|
|
||||||
MP_UNITS_EXPORT template<Unit auto V>
|
|
||||||
inline constexpr bool unit_can_be_prefixed = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept to be used to define prefixes for a unit
|
* @brief A concept to be used to define prefixes for a unit
|
||||||
*/
|
*/
|
||||||
MP_UNITS_EXPORT template<typename T>
|
MP_UNITS_EXPORT template<typename T>
|
||||||
concept PrefixableUnit = detail::NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
concept PrefixableUnit = Unit<T> && detail::is_derived_from_specialization_of_named_unit<T>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
@@ -125,15 +125,6 @@ using namespace non_si;
|
|||||||
|
|
||||||
} // namespace si
|
} // namespace si
|
||||||
|
|
||||||
template<>
|
|
||||||
inline constexpr bool unit_can_be_prefixed<si::degree_Celsius> = false;
|
|
||||||
template<>
|
|
||||||
inline constexpr bool unit_can_be_prefixed<non_si::minute> = false;
|
|
||||||
template<>
|
|
||||||
inline constexpr bool unit_can_be_prefixed<non_si::hour> = false;
|
|
||||||
template<>
|
|
||||||
inline constexpr bool unit_can_be_prefixed<non_si::day> = false;
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline constexpr bool space_before_unit_symbol<non_si::degree> = false;
|
inline constexpr bool space_before_unit_symbol<non_si::degree> = false;
|
||||||
template<>
|
template<>
|
||||||
|
@@ -155,31 +155,6 @@ static_assert(!Unit<int>);
|
|||||||
static_assert(!Unit<std::chrono::seconds>);
|
static_assert(!Unit<std::chrono::seconds>);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NamedUnit
|
|
||||||
static_assert(detail::NamedUnit<struct si::metre>);
|
|
||||||
static_assert(detail::NamedUnit<struct natural::electronvolt>);
|
|
||||||
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))>);
|
|
||||||
static_assert(!detail::NamedUnit<decltype(mag<10> * si::second)>);
|
|
||||||
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<derived_unit<struct si::metre, per<struct si::second>>>);
|
|
||||||
static_assert(!detail::NamedUnit<struct one>);
|
|
||||||
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, 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>);
|
|
||||||
#if MP_UNITS_HOSTED
|
|
||||||
static_assert(!detail::NamedUnit<std::chrono::seconds>);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// PrefixableUnit
|
// PrefixableUnit
|
||||||
static_assert(PrefixableUnit<struct si::metre>);
|
static_assert(PrefixableUnit<struct si::metre>);
|
||||||
static_assert(PrefixableUnit<struct natural::electronvolt>);
|
static_assert(PrefixableUnit<struct natural::electronvolt>);
|
||||||
|
@@ -63,10 +63,6 @@ static_assert(1 * Qm == 1'000'000'000'000'000'000 * Tm);
|
|||||||
template<template<typename U> typename prefix, auto V1>
|
template<template<typename U> typename prefix, auto V1>
|
||||||
concept can_not_be_prefixed = Unit<decltype(V1)> && !requires { typename prefix<decltype(V1)>; };
|
concept can_not_be_prefixed = Unit<decltype(V1)> && !requires { typename prefix<decltype(V1)>; };
|
||||||
|
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::degree_Celsius>);
|
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::minute>);
|
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::hour>);
|
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::day>);
|
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::kilogram>);
|
static_assert(can_not_be_prefixed<si::milli_, si::kilogram>);
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::hectare>);
|
static_assert(can_not_be_prefixed<si::milli_, si::hectare>);
|
||||||
static_assert(can_not_be_prefixed<si::milli_, si::kilo<si::metre>>);
|
static_assert(can_not_be_prefixed<si::milli_, si::kilo<si::metre>>);
|
||||||
|
@@ -106,18 +106,18 @@ static_assert(Unit<decltype(metre / second)>);
|
|||||||
static_assert(Unit<decltype(nu_second / nu_second)>);
|
static_assert(Unit<decltype(nu_second / nu_second)>);
|
||||||
static_assert(Unit<decltype(kilometre)>);
|
static_assert(Unit<decltype(kilometre)>);
|
||||||
|
|
||||||
static_assert(detail::NamedUnit<metre_>);
|
static_assert(PrefixableUnit<metre_>);
|
||||||
static_assert(detail::NamedUnit<hertz_>);
|
static_assert(PrefixableUnit<hertz_>);
|
||||||
static_assert(detail::NamedUnit<newton_>);
|
static_assert(PrefixableUnit<newton_>);
|
||||||
static_assert(detail::NamedUnit<minute_>);
|
static_assert(PrefixableUnit<minute_>);
|
||||||
static_assert(detail::NamedUnit<radian_>);
|
static_assert(PrefixableUnit<radian_>);
|
||||||
static_assert(!detail::NamedUnit<decltype(kilogram)>);
|
static_assert(!PrefixableUnit<decltype(kilogram)>);
|
||||||
static_assert(!detail::NamedUnit<decltype(kilojoule)>);
|
static_assert(!PrefixableUnit<decltype(kilojoule)>);
|
||||||
static_assert(!detail::NamedUnit<decltype(si::kilo<gram>)>);
|
static_assert(!PrefixableUnit<decltype(si::kilo<gram>)>);
|
||||||
static_assert(!detail::NamedUnit<decltype(square(metre))>);
|
static_assert(!PrefixableUnit<decltype(square(metre))>);
|
||||||
static_assert(!detail::NamedUnit<decltype(cubic(metre))>);
|
static_assert(!PrefixableUnit<decltype(cubic(metre))>);
|
||||||
static_assert(!detail::NamedUnit<decltype(mag<60> * second)>);
|
static_assert(!PrefixableUnit<decltype(mag<60> * second)>);
|
||||||
static_assert(!detail::NamedUnit<decltype(kilometre)>);
|
static_assert(!PrefixableUnit<decltype(kilometre)>);
|
||||||
|
|
||||||
// named unit
|
// named unit
|
||||||
static_assert(is_of_type<metre, metre_>);
|
static_assert(is_of_type<metre, metre_>);
|
||||||
|
Reference in New Issue
Block a user