From cb861dd81a168f135e073997a4c990d43e7344aa Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 25 Oct 2022 07:27:08 +0200 Subject: [PATCH] feat: system's definition highly simplified by removing the need for a `system_reference` for most cases --- example/v2_framework.cpp | 199 +++++++------ src/core/include/units/bits/basic_concepts.h | 6 +- .../include/units/bits/expression_template.h | 41 +++ src/core/include/units/dimension.h | 265 +++++++++++------ src/core/include/units/quantity.h | 4 +- src/core/include/units/reference.h | 3 - src/core/include/units/unit.h | 94 +++++- .../isq/include/units/isq/base_dimensions.h | 16 +- src/systems/isq/include/units/isq/mechanics.h | 76 ++--- .../isq/include/units/isq/space_and_time.h | 70 +++-- .../isq/include/units/isq/thermodynamics.h | 9 +- src/systems/si-cgs/include/units/si/cgs/cgs.h | 10 - src/systems/si/CMakeLists.txt | 14 +- .../si/include/units/si/base_quantities.h | 43 --- src/systems/si/include/units/si/constants.h | 12 +- src/systems/si/include/units/si/mechanics.h | 68 ----- src/systems/si/include/units/si/si.h | 4 - .../si/include/units/si/space_and_time.h | 64 ---- .../si/include/units/si/thermodynamics.h | 39 --- src/systems/si/include/units/si/units.h | 17 +- test/unit_test/static/CMakeLists.txt | 3 - test/unit_test/static/dimension_test.cpp | 281 +++++++++--------- test/unit_test/static/test_tools.h | 202 +++++++------ test/unit_test/static/unit_test.cpp | 19 +- 24 files changed, 779 insertions(+), 780 deletions(-) delete mode 100644 src/systems/si/include/units/si/base_quantities.h delete mode 100644 src/systems/si/include/units/si/mechanics.h delete mode 100644 src/systems/si/include/units/si/space_and_time.h delete mode 100644 src/systems/si/include/units/si/thermodynamics.h diff --git a/example/v2_framework.cpp b/example/v2_framework.cpp index abc075cd..04a88915 100644 --- a/example/v2_framework.cpp +++ b/example/v2_framework.cpp @@ -28,8 +28,7 @@ using namespace units; using namespace units::si::unit_symbols; // clang-format off -inline constexpr struct activity_dim : decltype(1 / isq::time_dim) {} activity_dim; -inline constexpr struct activity : system_reference {} activity; +DERIVED_DIMENSION(activity, decltype(1 / isq::time)); // clang-format on // check for invalid prefixes @@ -46,85 +45,84 @@ static_assert(can_not_be_prefixed); static_assert(can_not_be_prefixed); // Named quantity/dimension and unit -static_assert( - is_same_v{}, int>>); +static_assert(is_same_v{}, int>>); // Named quantity/dimension and derived (unnamed) unit static_assert( - is_same_v>>{}, int>>); + is_same_v>>{}, int>>); // Derived (unnamed) quantity/dimension and derived (unnamed) unit -static_assert(is_same_v>, +static_assert(is_same_v>, derived_unit>>{}, int>>); // Base quantity as a result of dimensional transformation -static_assert(is_same_v{}, int>>); +static_assert(is_same_v{}, int>>); // Dimensionless -static_assert(is_same_v{}, int>>); +static_assert(is_same_v{}, int>>); // Comparisons // Same dimension type & different unit -// static_assert(1000 * si::length[m] == 1 * si::length[km]); +// static_assert(1000 * isq::length[m] == 1 * isq::length[km]); // Named and derived dimensions (same units) -static_assert(10 * si::length[m] / (2 * si::time[s]) == 5 * si::speed[m / s]); -static_assert(5 * si::speed[m / s] == 10 * si::length[m] / (2 * si::time[s])); +static_assert(10 * isq::length[m] / (2 * isq::time[s]) == 5 * isq::speed[m / s]); +static_assert(5 * isq::speed[m / s] == 10 * isq::length[m] / (2 * isq::time[s])); // Same named dimension & different but equivalent unit -static_assert(10 * si::frequency[1 / s] == 10 * si::frequency[Hz]); -static_assert(10 * si::frequency[Hz] == 10 * si::frequency[1 / s]); +static_assert(10 * isq::frequency[1 / s] == 10 * isq::frequency[Hz]); +static_assert(10 * isq::frequency[Hz] == 10 * isq::frequency[1 / s]); // Named and derived dimensions (different but equivalent units) -static_assert(10 / (2 * si::time[s]) == 5 * si::frequency[Hz]); -static_assert(5 * si::frequency[Hz] == 10 / (2 * si::time[s])); -static_assert(5 * si::force[N] * (2 * si::length[m]) == 10 * si::energy[J]); -static_assert(10 * si::energy[J] == 5 * si::force[N] * (2 * si::length[m])); +static_assert(10 / (2 * isq::time[s]) == 5 * isq::frequency[Hz]); +static_assert(5 * isq::frequency[Hz] == 10 / (2 * isq::time[s])); +static_assert(5 * isq::force[N] * (2 * isq::length[m]) == 10 * isq::energy[J]); +static_assert(10 * isq::energy[J] == 5 * isq::force[N] * (2 * isq::length[m])); // Different named dimensions template concept invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; }; -static_assert(invalid_comparison); +static_assert(invalid_comparison); // Arithmetics // Named and derived dimensions (same units) -static_assert(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s] == 10 * si::speed[m / s]); -static_assert(5 * si::speed[m / s] + 10 * si::length[m] / (2 * si::time[s]) == 10 * si::speed[m / s]); -static_assert(10 * si::length[m] / (2 * si::time[s]) - 5 * si::speed[m / s] == 0 * si::speed[m / s]); -static_assert(5 * si::speed[m / s] - 10 * si::length[m] / (2 * si::time[s]) == 0 * si::speed[m / s]); +static_assert(10 * isq::length[m] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]); +static_assert(5 * isq::speed[m / s] + 10 * isq::length[m] / (2 * isq::time[s]) == 10 * isq::speed[m / s]); +static_assert(10 * isq::length[m] / (2 * isq::time[s]) - 5 * isq::speed[m / s] == 0 * isq::speed[m / s]); +static_assert(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s]) == 0 * isq::speed[m / s]); static_assert( - is_same_v>>{}, int>>); + is_same_v>>{}, int>>); static_assert( - is_same_v>>{}, int>>); + is_same_v>>{}, int>>); static_assert( - is_same_v>>{}, int>>); + is_same_v>>{}, int>>); static_assert( - is_same_v>>{}, int>>); + is_same_v>>{}, int>>); // Named and derived dimensions (different units) -static_assert(10 / (2 * si::time[s]) + 5 * si::frequency[Hz] == 10 * si::frequency[Hz]); -static_assert(5 * si::frequency[Hz] + 10 / (2 * si::time[s]) == 10 * si::frequency[Hz]); -static_assert(10 / (2 * si::time[s]) - 5 * si::frequency[Hz] == 0 * si::frequency[Hz]); -static_assert(5 * si::frequency[Hz] - 10 / (2 * si::time[s]) == 0 * si::frequency[Hz]); -static_assert(is_same_v{}, int>>); -static_assert(is_same_v{}, int>>); -static_assert(is_same_v{}, int>>); -static_assert(is_same_v{}, int>>); +static_assert(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz] == 10 * isq::frequency[Hz]); +static_assert(5 * isq::frequency[Hz] + 10 / (2 * isq::time[s]) == 10 * isq::frequency[Hz]); +static_assert(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz] == 0 * isq::frequency[Hz]); +static_assert(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s]) == 0 * isq::frequency[Hz]); +static_assert(is_same_v{}, int>>); +static_assert(is_same_v{}, int>>); +static_assert(is_same_v{}, int>>); +static_assert(is_same_v{}, int>>); // Different named dimensions template @@ -132,50 +130,49 @@ consteval bool invalid_arithmetic(Ts... ts) { return !requires { (... + ts); } && !requires { (... - ts); }; } -static_assert(invalid_arithmetic(5 * activity[Bq], 5 * si::frequency[Hz])); -static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * si::time[s]), 5 * si::frequency[Hz])); +static_assert(invalid_arithmetic(5 * activity[Bq], 5 * isq::frequency[Hz])); +static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); // Implicit conversions allowed between quantities of `convertible` references -constexpr quantity speed = 120 * si::length[km] / (2 * si::time[h]); +constexpr quantity speed = 120 * isq::length[km] / (2 * isq::time[h]); // Explicit casts allow changing all or only a part of the type static_assert( - std::is_same_v< - decltype(quantity_cast(120 * si::length[km] / (2 * si::time[h]))), - quantity)>, per>>{}, - int>>); -auto q3 = quantity_cast(120 * si::length[km] / (2 * si::time[h])); -auto q4 = quantity_cast(120 * si::length[km] / (2 * si::time[h])); -auto q5 = quantity_cast(120 * si::length[km] / (2 * si::time[h])); -auto q6 = quantity_cast>(120 * si::length[km] / (2 * si::time[h])); + std::is_same_v(120 * isq::length[km] / (2 * isq::time[h]))), + quantity)>, + per>>{}, + int>>); +auto q3 = quantity_cast(120 * isq::length[km] / (2 * isq::time[h])); +auto q4 = quantity_cast(120 * isq::length[km] / (2 * isq::time[h])); +auto q5 = quantity_cast(120 * isq::length[km] / (2 * isq::time[h])); +auto q6 = quantity_cast>(120 * isq::length[km] / (2 * isq::time[h])); -// cast 1 / time_dim to use Hz +// cast 1 / time to use Hz -// static_assert(quantity_of); -// static_assert(quantity_of); -// static_assert(quantity_of); -// static_assert(!quantity_of); +// static_assert(quantity_of); +// static_assert(quantity_of); +// static_assert(quantity_of); +// static_assert(!quantity_of); -// quantity>>, int> s = 5 * speed[m / s]; -// quantity>, derived_unit>>, int> q = -// 10 * length[m] / (2 * si::time[s]); +// quantity>>, int> s = 5 * speed[m / s]; +// quantity>, derived_unit>>, int> q = +// 10 * length[m] / (2 * isq::time[s]); -// auto q1 = 10 * length[m] / (2 * si::time[s]) + 5 * speed[m / s]; // should this be allowed? -// bool b1 = (10 * length[m] / (2 * si::time[s]) == 5 * speed[m / s]); // should this be allowed? +// auto q1 = 10 * length[m] / (2 * isq::time[s]) + 5 * speed[m / s]; // should this be allowed? +// bool b1 = (10 * length[m] / (2 * isq::time[s]) == 5 * speed[m / s]); // should this be allowed? -// auto q2 = 10 / (2 * si::time[s]) + 5 * frequency[Hz]; // should this be allowed? -// bool b2 = (10 / (2 * si::time[s]) == 5 * frequency[Hz]); // should this be allowed? +// auto q2 = 10 / (2 * isq::time[s]) + 5 * frequency[Hz]; // should this be allowed? +// bool b2 = (10 / (2 * isq::time[s]) == 5 * frequency[Hz]); // should this be allowed? // auto q3 = 5 * activity[Bq] + 5 * frequency[Hz]; // should this be allowed? // auto b3 = (5 * activity[Bq] == 5 * frequency[Hz]); // should this be allowed? -// auto q4 = 5 * activity[Bq] + 10 / (2 * si::time[s]) + 5 * frequency[Hz]; // should this be allowed? +// auto q4 = 5 * activity[Bq] + 10 / (2 * isq::time[s]) + 5 * frequency[Hz]; // should this be allowed? -// auto q5 = 120 * length[km] / (2 * si::time[h]); // not speed -// auto q6 = quantity_cast(120 * length[km] / (2 * si::time[h])); -// auto q7 = quantity_cast(120 * length[km] / (2 * si::time[h])); +// auto q5 = 120 * length[km] / (2 * isq::time[h]); // not speed +// auto q6 = quantity_cast(120 * length[km] / (2 * isq::time[h])); +// auto q7 = quantity_cast(120 * length[km] / (2 * isq::time[h])); // quantity s = q5; // should this implicit conversion be allowed? } // namespace @@ -192,10 +189,12 @@ namespace units::isq::si { // quantity tests // static_assert( -// is_exactly_quantity_of>>); +// is_exactly_quantity_of>>); -// static_assert(QuantityOf>); -// static_assert(QuantityOf>); +// static_assert(QuantityOf>); static_assert(QuantityOf>); // // TODO Should this compile? } // namespace units::isq::si @@ -205,21 +204,37 @@ namespace units::isq::si { // using namespace units::si::unit_symbols; // /* Frequency */ auto freq1 = 20 * frequency[Hz]; -// // /* Frequency */ auto freq2 = 20 / (1 * si::time[s]); +// // /* Frequency */ auto freq2 = 20 / (1 * isq::time[s]); // quantity freq3(20); // quantity freq4(20); -// quantity freq5(20); +// quantity freq5(20); // /* Speed */ auto speed1 = 20 * speed[m / s]; -// /* Speed */ auto speed2 = 20 * (length[m] / si::time[s]); +// /* Speed */ auto speed2 = 20 * (length[m] / isq::time[s]); // quantity speed3(20); -// quantity speed4(20); +// quantity speed4(20); -// constexpr auto avg_speed(quantity d, quantity t) { return d / t; } +// constexpr auto avg_speed(quantity d, quantity t) { return d / t; } + +#include int main() { + using enum text_encoding; + using enum unit_symbol_denominator; + using enum unit_symbol_separator; + + std::cout << unit_symbol(si::kilogram / si::metre / square, {.denominator = always_solidus}) << "\n"; + // std::cout << unit_symbol(si::metre / si::second, {.denominator = unit_symbol_denominator::always_negative}) << + // "\n"; std::cout << unit_symbol(si::metre / si::second, {.denominator = unit_symbol_denominator::always_negative}) + // << + // "\n"; + // static_assert(unit_symbol(metre / second, {.denominator = always_negative, .separator = dot}) == "m⋅s⁻¹"); + + // std::cout << get_unit_symbol(si::minute / square).standard().c_str() << "\n"; + // std::cout << get_unit_symbol(si::joule / si::minute).standard().c_str() << "\n"; + // print(); // print(); // // print(); @@ -239,19 +254,19 @@ int main() // joule * erg??? // joule / erg??? -// auto d1 = 42 * isq::length_dim[si::kilo]; -// auto d2 = 42 * isq::length_dim[cgs::centimetre]; +// auto d1 = 42 * isq::length[si::kilo]; +// auto d2 = 42 * isq::length[cgs::centimetre]; -// auto s1 = 42 * isq::speed_dim[si::metre / si::second]; -// auto s2 = 42 * isq::speed_dim[cgs::centimetre / si::second]; -// auto e1 = 42 * isq::energy_dim[si::joule]; -// auto e2 = 42 * isq::energy_dim[cgs::erg]; -// auto e2_bad = 42 * isq::energy_dim[cgs::erg / si::second]; -// auto p1 = 42 * isq::power_dim[si::watt]; -// auto p2 = 42 * isq::power_dim[cgs::erg / si::second]; +// auto s1 = 42 * isq::speed[si::metre / si::second]; +// auto s2 = 42 * isq::speed[cgs::centimetre / si::second]; +// auto e1 = 42 * isq::energy[si::joule]; +// auto e2 = 42 * isq::energy[cgs::erg]; +// auto e2_bad = 42 * isq::energy[cgs::erg / si::second]; +// auto p1 = 42 * isq::power[si::watt]; +// auto p2 = 42 * isq::power[cgs::erg / si::second]; // type of Rep{1} * (mag * mag_power<10, -34> * energy[joule] * time[second]) // and inline constexpr auto planck_constant = Rep{1} * mag_planck * energy[joule] * time[second]; -// quantity_cast on equivalent dimensions \ No newline at end of file +// quantity_cast on equivalent dimensions diff --git a/src/core/include/units/bits/basic_concepts.h b/src/core/include/units/bits/basic_concepts.h index ac073b28..9cea3de7 100644 --- a/src/core/include/units/bits/basic_concepts.h +++ b/src/core/include/units/bits/basic_concepts.h @@ -102,7 +102,11 @@ template concept AliasUnit = requires(T* t) { detail::to_base_alias_unit(t); }; // BaseDimension -template +#ifdef __cpp_explicit_this_parameter__ +template +#else +template +#endif struct base_dimension; namespace detail { diff --git a/src/core/include/units/bits/expression_template.h b/src/core/include/units/bits/expression_template.h index b2bdee1e..63264d69 100644 --- a/src/core/include/units/bits/expression_template.h +++ b/src/core/include/units/bits/expression_template.h @@ -457,6 +457,9 @@ template typename To * * @tparam Num Exponent numerator * @tparam Den Exponent denominator + * @tparam To destination type list to put the result to + * @tparam OneType type that represents the value `1` + * @tparam Pred binary less then predicate * @tparam T Expression being the base of the operation */ template typename To, typename OneType, @@ -467,6 +470,44 @@ template typename To return expr_pow_impl(typename T::_num_{}, typename T::_den_{}); } + +// expr_map + +template typename Proj> +struct expr_type_map { + using type = Proj; +}; + +template typename Proj> +struct expr_type_map, Proj> { + using type = power, Ints...>; +}; + +template typename Proj, template typename To, typename OneType, + template typename Pred, typename... Nums, typename... Dens> +[[nodiscard]] consteval auto expr_map_impl(type_list, type_list) +{ + using nums = type_list_sort::type...>, Pred>; + using dens = type_list_sort::type...>, Pred>; + return detail::get_optimized_expression(); +} + +/** + * @brief Maps contents of one expression template to another resulting in a different type list + * + * @tparam Proj Projection to be used for mapping + * @tparam To destination type list to put the result to + * @tparam OneType type that represents the value `1` + * @tparam Pred binary less then predicate + * @tparam T expression template to map from + */ +template typename Proj, template typename To, typename OneType, + template typename Pred, typename T> +[[nodiscard]] consteval auto expr_map(T) +{ + return expr_map_impl(typename T::_num_{}, typename T::_den_{}); +} + } // namespace detail } // namespace units diff --git a/src/core/include/units/dimension.h b/src/core/include/units/dimension.h index 742148fb..63d99316 100644 --- a/src/core/include/units/dimension.h +++ b/src/core/include/units/dimension.h @@ -25,64 +25,10 @@ #include #include #include +#include namespace units { -/** - * @brief A dimension of a base quantity - * - * Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity - * in the subset can be expressed in terms of the other quantities within that subset. They are referred to as - * being mutually independent since a base quantity cannot be expressed as a product of powers of the other base - * quantities. - * - * Symbol template parameters is an unique identifier of the base dimension. The same identifiers can be multiplied - * and divided which will result with an adjustment of its factor in an exponent of a derived_dimension - * (in case of zero the dimension will be simplified and removed from further analysis of current expresion). - * - * User should derive a strong type from this class template rather than use it directly in the source code. - * For example: - * - * @code{.cpp} - * inline constexpr struct length_dim : base_dimension<"L"> {} length_dim; - * inline constexpr struct time_dim : base_dimension<"T"> {} time_dim; - * inline constexpr struct mass_dim : base_dimension<"M"> {} mass_dim; - * @endcode - * - * @note A common convention in this library is to assign the same name for a type and an object of this type. - * Besides defining them user never works with the dimension types in the source code. All operations - * are done on the objects. Contrarily, the dimension types are the only one visible in the compilation - * errors. Having them of the same names improves user experience and somehow blurs those separate domains. - * - * @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support - */ -template -struct base_dimension { - static constexpr auto symbol = Symbol; ///< Unique base dimension identifier -}; - -namespace detail { - -template -void to_base_base_dimension(const volatile base_dimension*); - -template -inline constexpr bool is_specialization_of_base_dimension = false; - -template -inline constexpr bool is_specialization_of_base_dimension> = true; - -} // namespace detail - -/** - * @brief A concept matching all named base dimensions in the library. - * - * Satisfied by all dimension types derived from a specialization of `base_dimension`. - */ -template -concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); } && - (!detail::is_specialization_of_base_dimension); - namespace detail { template @@ -107,6 +53,66 @@ concept DerivedDimension = detail::is_derived_dimension; template concept Dimension = BaseDimension || DerivedDimension; + +namespace detail { + +[[nodiscard]] consteval Dimension auto get_dimension_for(Unit auto); + +} + +template +struct reference; + +/** + * @brief A dimension of a base quantity + * + * Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity + * in the subset can be expressed in terms of the other quantities within that subset. They are referred to as + * being mutually independent since a base quantity cannot be expressed as a product of powers of the other base + * quantities. + * + * Symbol template parameters is an unique identifier of the base dimension. The same identifiers can be multiplied + * and divided which will result with an adjustment of its factor in an exponent of a derived_dimension + * (in case of zero the dimension will be simplified and removed from further analysis of current expresion). + * + * User should derive a strong type from this class template rather than use it directly in the source code. + * For example: + * + * @code{.cpp} + * inline constexpr struct length : base_dimension<"L"> {} length; + * inline constexpr struct time : base_dimension<"T"> {} time; + * inline constexpr struct mass : base_dimension<"M"> {} mass; + * @endcode + * + * @note A common convention in this library is to assign the same name for a type and an object of this type. + * Besides defining them user never works with the dimension types in the source code. All operations + * are done on the objects. Contrarily, the dimension types are the only one visible in the compilation + * errors. Having them of the same names improves user experience and somehow blurs those separate domains. + * + * @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support + */ +#ifdef __cpp_explicit_this_parameter__ +template +#else +template +#endif +struct base_dimension { + static constexpr auto symbol = Symbol; ///< Unique base dimension identifier + +#ifdef __cpp_explicit_this_parameter__ + template + requires(convertible(Self{}, detail::get_dimension_for(U{}))) + [[nodiscard]] constexpr reference operator[](this const Self, U) +#else + template + requires(convertible(Self{}, detail::get_dimension_for(U{}))) + [[nodiscard]] constexpr reference operator[](U) const +#endif + { + return {}; + } +}; + namespace detail { template @@ -116,12 +122,13 @@ template using type_list_of_base_dimension_less = expr_less; template -inline constexpr bool is_one_dim = false; +inline constexpr bool is_dimensionless = false; template inline constexpr bool is_power_of_dim = requires { - requires is_specialization_of_power && (BaseDimension || is_one_dim); + requires is_specialization_of_power && + (BaseDimension || is_dimensionless); }; template @@ -129,15 +136,15 @@ inline constexpr bool is_per_of_dims = false; template inline constexpr bool is_per_of_dims> = - (... && (BaseDimension || is_one_dim || is_power_of_dim)); + (... && (BaseDimension || is_dimensionless || is_power_of_dim)); } // namespace detail template concept DerivedDimensionSpec = - BaseDimension || detail::is_one_dim || detail::is_power_of_dim || detail::is_per_of_dims; + BaseDimension || detail::is_dimensionless || detail::is_power_of_dim || detail::is_per_of_dims; -template +template struct derived_dimension; namespace detail { @@ -160,47 +167,83 @@ struct derived_dimension_impl : detail::expr_fractions, Ds.. * more digestable for the user. The positive exponents are ordered first and all negative exponents are put as a list * into the `per<...>` class template. If a power of exponent is different than `1` the dimension type is enclosed in * `power` class template. Otherwise, it is just put directly in the list without any wrapper. There - * is also one special case. In case all of the exponents are negative than the `one_dim` being a dimension of + * is also one special case. In case all of the exponents are negative than the `dimensionless` being a dimension of * a dimensionless quantity is put in the front to increase the readability. * * For example: * * @code{.cpp} - * inline constexpr struct frequency_dim : decltype(1 / time_dim) {} frequency_dim; - * inline constexpr struct speed_dim : decltype(length_dim / time_dim) {} speed_dim; - * inline constexpr struct acceleration_dim : decltype(speed_dim / time_dim) {} acceleration_dim; - * inline constexpr struct force_dim : decltype(mass_dim * acceleration_dim) {} force_dim; - * inline constexpr struct energy_dim : decltype(force_dim * length_dim) {} energy_dim; - * inline constexpr struct moment_of_force_dim : decltype(length_dim * force_dim) {} moment_of_force_dim; - * inline constexpr struct torque_dim : decltype(moment_of_force_dim) {} torque_dim; + * DERIVED_DIMENSION(frequency, 1 / time); + * DERIVED_DIMENSION(speed, length / time); + * DERIVED_DIMENSION(acceleration, speed / time); + * DERIVED_DIMENSION(force, mass * acceleration); + * DERIVED_DIMENSION(energy, force * length); + * DERIVED_DIMENSION(moment_of_force, length * force); + * DERIVED_DIMENSION(torque, moment_of_force); * @endcode * - * - `frequency_dim` will be derived from type `derived_dimension>` - * - `speed_dim` will be derived from type `derived_dimension>` - * - `acceleration_dim` will be derived from type `derived_dimension>>` - * - `force_dim` will be derived from type `derived_dimension>>` - * - `energy_dim` will be derived from type `derived_dimension, mass_dim, per>>` + * - `frequency` will be derived from type `derived_dimension>` + * - `speed` will be derived from type `derived_dimension>` + * - `acceleration` will be derived from type `derived_dimension>>` + * - `force` will be derived from type `derived_dimension>>` + * - `energy` will be derived from type `derived_dimension, mass, per>>` * * @note A common convention in this library is to assign the same name for a type and an object of this type. * Besides defining them user never works with the dimension types in the source code. All operations * are done on the objects. Contrarily, the dimension types are the only one visible in the compilation * errors. Having them of the same names improves user experience and somehow blurs those separate domains. * - * Two dimensions are deemed equal when they are of the same type. With that strong type `speed_dim` and - * `derived_dimension>` are considered not equal. They are convertible though. + * Two dimensions are deemed equal when they are of the same type. With that strong type `speed` and + * `derived_dimension>` are considered not equal. They are convertible though. * User can implicitly convert up and down the inheritance hierarchy between those two. - * `torque_dim` and `moment_of_force_dim` are convertible as well. However, `energy_dim` and `torque_dim` + * `torque` and `moment_of_force` are convertible as well. However, `energy` and `torque` * are not convertible as they do not inherit from each other. They are from two separate branches of * dimensionally equivalent quantities. * * @tparam Ds a parameter pack consisting tokens allowed in the dimension specification - * (base dimensions, `one_dim`, `power`, `per<...>`) + * (base dimensions, `dimensionless`, `power`, `per<...>`) * * @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. */ +#ifdef __cpp_explicit_this_parameter__ + template -struct derived_dimension : detail::derived_dimension_impl {}; +struct derived_dimension : detail::derived_dimension_impl { + template + requires(convertible(Self{}, detail::get_dimension_for(U{}))) + [[nodiscard]] constexpr reference operator[](this const Self, U) + { + return {}; + } +}; + +#else + +template +struct derived_dimension; + +template +struct derived_dimension : detail::derived_dimension_impl { + template + requires(convertible(derived_dimension{}, detail::get_dimension_for(U{}))) + [[nodiscard]] constexpr reference operator[](U) const + { + return {}; + } +}; + +template +struct derived_dimension : D { + template + requires(convertible(Self{}, detail::get_dimension_for(U{}))) + [[nodiscard]] constexpr reference operator[](U) const + { + return {}; + } +}; + +#endif namespace detail { @@ -223,13 +266,13 @@ inline constexpr bool is_derived_dimension = true; * Dimension for which all the exponents of the factors corresponding to the base * dimensions are zero. Also commonly named as "dimensionless". */ -inline constexpr struct one_dim : derived_dimension<> { -} one_dim; +inline constexpr struct dimensionless : derived_dimension<> { +} dimensionless; namespace detail { template<> -inline constexpr bool is_one_dim = true; +inline constexpr bool is_dimensionless = true; template struct dim_type_impl { @@ -252,14 +295,14 @@ using dim_type = dim_type_impl::type; template [[nodiscard]] consteval Dimension auto operator*(Lhs, Rhs) { - return detail::expr_multiply( + return detail::expr_multiply( detail::dim_type{}, detail::dim_type{}); } template [[nodiscard]] consteval Dimension auto operator/(Lhs, Rhs) { - return detail::expr_divide( + return detail::expr_divide( detail::dim_type{}, detail::dim_type{}); } @@ -267,7 +310,7 @@ template [[nodiscard]] consteval Dimension auto operator/(int value, D) { gsl_Expects(value == 1); - return detail::expr_invert(detail::dim_type{}); + return detail::expr_invert(detail::dim_type{}); } template @@ -304,9 +347,38 @@ template else return derived_dimension>{}; } else - return detail::expr_pow(d); + return detail::expr_pow(d); } +namespace detail { + +template +[[nodiscard]] consteval Dimension auto get_dimension_for_impl(U) + requires requires { U::base_dimension; } +{ + return U::base_dimension; +} + +template + requires requires { U::base_dimension; } +using to_base_dimension = std::remove_const_t; + +template +[[nodiscard]] consteval Dimension auto get_dimension_for_impl(const derived_unit& u) +{ + return detail::expr_map(u); +} + +[[nodiscard]] consteval Dimension auto get_dimension_for(Unit auto u) +{ + return get_dimension_for_impl(get_canonical_unit(u).reference_unit); +} + +} // namespace detail + + // TODO consider adding the support for text output of the dimensional equation } // namespace units @@ -327,3 +399,26 @@ struct common_type { }; } // namespace std + + +#ifdef __cpp_explicit_this_parameter__ + +#define BASE_DIMENSION(name, symbol) \ + inline constexpr struct name : base_dimension { \ + } name + +#define DERIVED_DIMENSION(name, base) \ + inline constexpr struct name : base { \ + } name + +#else + +#define BASE_DIMENSION(name, symbol) \ + inline constexpr struct name : base_dimension { \ + } name + +#define DERIVED_DIMENSION(name, base) \ + inline constexpr struct name : derived_dimension { \ + } name + +#endif diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index f48c3d7f..62eb4d6e 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -48,7 +48,7 @@ inline constexpr auto make_quantity = [](Representation auto&& v) { }; template -concept quantity_one = Quantity && (T::dimension == one_dim) && (T::unit == one); +concept quantity_one = Quantity && (T::dimension == dimensionless) && (T::unit == one); } // namespace detail @@ -506,7 +506,7 @@ template template requires(!floating_point_) && (!floating_point_) && - (std::convertible_to || quantity_of) && + (std::convertible_to || quantity_of) && (quantity_value_for_, typename Q1::rep, typename Q2::rep>) [[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs) { diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index eaa8c65b..d88851ef 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -162,9 +162,6 @@ struct system_reference { } }; -inline constexpr struct dimensionless : system_reference { -} dimensionless; - } // namespace units namespace std { diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 31cd3827..08cfc414 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -29,19 +29,52 @@ #include #include #include +#include #include #include #include -// #include - -// IWYU pragma: begin_exports -// #include -// #include -// IWYU pragma: end_exports - namespace units { +#ifdef __cpp_explicit_this_parameter__ +template +#else +template +#endif +struct base_dimension; + +namespace detail { + +#ifdef __cpp_explicit_this_parameter__ +template +void to_base_base_dimension(const volatile base_dimension*); +#else +template +void to_base_base_dimension(const volatile base_dimension*); +#endif + +template +inline constexpr bool is_specialization_of_base_dimension = false; + +#ifdef __cpp_explicit_this_parameter__ +template +inline constexpr bool is_specialization_of_base_dimension> = true; +#else +template +inline constexpr bool is_specialization_of_base_dimension> = true; +#endif + +} // namespace detail + +/** + * @brief A concept matching all named base dimensions in the library. + * + * Satisfied by all dimension types derived from a specialization of `base_dimension`. + */ +template +concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); } && + (!detail::is_specialization_of_base_dimension); + namespace detail { template @@ -86,14 +119,16 @@ inline constexpr bool is_specialization_of_scaled_unit> = true /** * @brief A named unit * - * Defines a unit with a special name. + * Defines a unit with a special name. It may be used to provide a base unit in the system + * of units (i.e. `metre`) or a name assigned to another scaled or derived unit + * (i.e. `hour`, `joule`). * Most of the named units may be composed with a prefix to create a `prefixed_unit`. * * For example: * * @code{.cpp} - * inline constexpr struct second : named_unit<"s"> {} second; - * inline constexpr struct metre : named_unit<"m"> {} metre; + * 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", 1 / second> {} hertz; * inline constexpr struct newton : named_unit<"N", kilogram * metre / square> {} newton; * inline constexpr struct degree_Celsius : named_unit {} degree_Celsius; @@ -111,11 +146,33 @@ template struct named_unit; /** - * @brief Specialization for base unit + * @brief Specialization for unit of a specified base dimension * - * Defines a base unit in the system of units (i.e. `metre`). - * or a name assigned to another scaled or derived unit (i.e. `hour`, `joule`). - * Most of the named units may be composed with a prefix to create a `prefixed_unit`. + * This is the preferred way to define a measurement unit for a base dimension. For example `si::metre` + * is a unit to measure `isq::length` in the SI system. + * + * @note It does not have to (or sometimes even can't) be a proper system's base unit. For example + * a base unit of mass in the SI is `si::kilogram` but here you are about to provide an `si::gram` + * and it will work just fine as those two are convertible to each other. A similar case would be + * the `cgs::centimetre` that is a base unit for `isq::length` in the CGS system. + * + * @tparam Symbol a short text representation of the unit + * @tparam BaseDimension base dimension measured with this unit + */ +template + requires(!Symbol.empty()) +struct named_unit { + static constexpr auto symbol = Symbol; ///< Unique base unit identifier + static constexpr auto base_dimension = D; +}; + +/** + * @brief Specialization for a unit that can be reused by several base dimensions + * + * This specialization is used in rare cases where more than one base dimension in a specific + * system of units uses the same unit. For example in a hypothetical system of units where + * constant for speed of light `c = 1`, length and time could be measured in seconds. In such + * cases `system_reference` has to be used to explicitly express such a binding. * * @tparam Symbol a short text representation of the unit */ @@ -319,6 +376,9 @@ struct canonical_unit { U reference_unit; }; +template +[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&); + template [[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&); @@ -338,6 +398,12 @@ template return canonical_unit{M * base.mag, base.reference_unit}; } +template +[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&) +{ + return canonical_unit{mag<1>, t}; +} + template [[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&) { diff --git a/src/systems/isq/include/units/isq/base_dimensions.h b/src/systems/isq/include/units/isq/base_dimensions.h index cabf9b61..a0e7b2ad 100644 --- a/src/systems/isq/include/units/isq/base_dimensions.h +++ b/src/systems/isq/include/units/isq/base_dimensions.h @@ -26,15 +26,13 @@ namespace units::isq { -// clang-format off -inline constexpr struct length_dim : base_dimension<"L"> {} length_dim; -inline constexpr struct mass_dim : base_dimension<"M"> {} mass_dim; -inline constexpr struct time_dim : base_dimension<"T"> {} time_dim; -inline constexpr struct electric_current_dim : base_dimension<"I"> {} electric_current_dim; +BASE_DIMENSION(length, "L"); +BASE_DIMENSION(mass, "M"); +BASE_DIMENSION(time, "T"); +BASE_DIMENSION(electric_current, "I"); // TODO Should the below use basic_symbol_text? How to name it for ASCII? -inline constexpr struct thermodynamic_temperature_dim : base_dimension<"Θ"> {} thermodynamic_temperature_dim; -inline constexpr struct amount_of_substance_dim : base_dimension<"N"> {} amount_of_substance_dim; -inline constexpr struct luminous_intensity_dim : base_dimension<"J"> {} luminous_intensity_dim; -// clang-format on +BASE_DIMENSION(thermodynamic_temperature, "Θ"); +BASE_DIMENSION(amount_of_substance, "N"); +BASE_DIMENSION(luminous_intensity, "J"); } // namespace units::isq diff --git a/src/systems/isq/include/units/isq/mechanics.h b/src/systems/isq/include/units/isq/mechanics.h index 3f4271d9..aa6d7ca8 100644 --- a/src/systems/isq/include/units/isq/mechanics.h +++ b/src/systems/isq/include/units/isq/mechanics.h @@ -28,45 +28,45 @@ namespace units::isq { -// clang-format off -// inline constexpr struct mass_dim : base_dimension<"M"> {} mass_dim; -inline constexpr struct mass_density_dim : decltype(mass_dim / volume_dim) {} mass_density_dim; -inline constexpr struct specific_volume_dim : decltype(1 / mass_density_dim) {} specific_volume_dim; -inline constexpr struct relative_mass_density_dim : decltype(mass_density_dim / mass_density_dim) {} relative_mass_density_dim; -inline constexpr struct surface_mass_density_dim : decltype(mass_dim / area_dim) {} surface_mass_density_dim; -inline constexpr struct linear_mass_density_dim : decltype(mass_dim / length_dim) {} linear_mass_density_dim; -inline constexpr struct momentum_dim : decltype(mass_dim * speed_dim) {} momentum_dim; // TODO velocity_dim? -inline constexpr struct force_dim : decltype(mass_dim * acceleration_dim) {} force_dim; // TODO what is a correct equation here? -// inline constexpr struct weight_dim : decltype(mass_dim * acceleration_dim) {} weight_dim; // TODO should we add it as a quantity or should it be a quantity_kind? -// TODO Should we add other forces as well: static_friction_force, kinematic_friction_force, rolling_resistance, drag_force -inline constexpr struct impulse_dim : decltype(force_dim / time_dim) {} impulse_dim; -inline constexpr struct angular_momentum_dim : decltype(length_dim * momentum_dim) {} angular_momentum_dim; // TODO position_vector -inline constexpr struct moment_of_inertia_dim : decltype(angular_momentum_dim * angular_velocity_dim) {} moment_of_inertia_dim; -inline constexpr struct moment_of_force_dim : decltype(length_dim * force_dim) {} moment_of_force_dim; // TODO position_vector -inline constexpr struct torque_dim : decltype(moment_of_force_dim) {} torque_dim; // TODO angle? -inline constexpr struct angular_impulse_dim : decltype(moment_of_force_dim * time_dim) {} angular_impulse_dim; -inline constexpr struct pressure_dim : decltype(force_dim / area_dim) {} pressure_dim; -inline constexpr struct stress_dim : decltype(pressure_dim) {} stress_dim; // TODO tensor? -inline constexpr struct normal_stress_dim : decltype(force_dim / area_dim) {} normal_stress_dim; -inline constexpr struct strain_dim : decltype(stress_dim / stress_dim) {} strain_dim; // TODO what is a correct equation here? -inline constexpr struct poisson_number_dim : decltype(length_dim / length_dim) {} poisson_number_dim; // TODO width? +// inline constexpr struct mass : base_dimension<"M"> {} mass; +DERIVED_DIMENSION(mass_density, decltype(mass / volume)); +DERIVED_DIMENSION(specific_volume, decltype(1 / mass_density)); +DERIVED_DIMENSION(relative_mass_density, decltype(mass_density / mass_density)); +DERIVED_DIMENSION(surface_mass_density, decltype(mass / area)); +DERIVED_DIMENSION(linear_mass_density, decltype(mass / length)); +DERIVED_DIMENSION(momentum, decltype(mass * speed)); // TODO velocity? +DERIVED_DIMENSION(force, decltype(mass * acceleration)); // TODO what is a correct equation here? +// DERIVED_DIMENSION(weight, decltype(mass * acceleration)); // TODO should we add it as a quantity or should it be a +// quantity_kind? +// TODO Should we add other forces as well: static_friction_force, kinematic_friction_force, rolling_resistance, +// drag_force +DERIVED_DIMENSION(impulse, decltype(force / time)); +DERIVED_DIMENSION(angular_momentum, decltype(length * momentum)); // TODO position_vector +DERIVED_DIMENSION(moment_of_inertia, decltype(angular_momentum * angular_velocity)); +DERIVED_DIMENSION(moment_of_force, decltype(length * force)); // TODO position_vector +DERIVED_DIMENSION(torque, decltype(moment_of_force)); // TODO angle? +DERIVED_DIMENSION(angular_impulse, decltype(moment_of_force * time)); +DERIVED_DIMENSION(pressure, decltype(force / area)); +DERIVED_DIMENSION(stress, decltype(pressure)); // TODO tensor? +DERIVED_DIMENSION(normal_stress, decltype(force / area)); +DERIVED_DIMENSION(strain, decltype(stress / stress)); // TODO what is a correct equation here? +DERIVED_DIMENSION(poisson_number, decltype(length / length)); // TODO width? // TODO modulus quantities -inline constexpr struct compressibility_dim : decltype(volume_dim / pressure_dim) {} compressibility_dim; -inline constexpr struct second_axial_moment_of_area_dim : decltype(area_dim * area_dim) {} second_axial_moment_of_area_dim; // TODO what is a correct equation here? -inline constexpr struct section_modulus_dim : decltype(second_axial_moment_of_area_dim / length_dim) {} section_modulus_dim; // TODO radial distance +DERIVED_DIMENSION(compressibility, decltype(volume / pressure)); +DERIVED_DIMENSION(second_axial_moment_of_area, decltype(area * area)); // TODO what is a correct equation here? +DERIVED_DIMENSION(section_modulus, decltype(second_axial_moment_of_area / length)); // TODO radial distance // TODO friction coefficients? -inline constexpr struct dynamic_viscosity_dim : decltype(stress_dim * length_dim / speed_dim) {} dynamic_viscosity_dim; // TODO shear stress, velocity -inline constexpr struct kinematic_viscosity_dim : decltype(dynamic_viscosity_dim / mass_density_dim) {} kinematic_viscosity_dim; -inline constexpr struct surface_tension_dim : decltype(force_dim / length_dim) {} surface_tension_dim; // TODO what is a correct equation here? -inline constexpr struct power_dim : decltype(force_dim * speed_dim) {} power_dim; -// TODO what about energy (potential and kinetic as separate quantities will prevent an equation for mechanical one, is it expected?) -inline constexpr struct efficiency_dim : decltype(power_dim / power_dim) {} efficiency_dim; -inline constexpr struct mass_flow_dim : decltype(mass_density_dim * speed_dim) {} mass_flow_dim; // TODO velocity -inline constexpr struct mass_flow_rate_dim : decltype(mass_flow_dim * area_dim) {} mass_flow_rate_dim; -inline constexpr struct mass_change_rate_dim : decltype(mass_dim / time_dim) {} mass_change_rate_dim; -inline constexpr struct volume_flow_rate_dim : decltype(speed_dim * area_dim) {} volume_flow_rate_dim; // TODO velocity -// inline constexpr struct action_dim : decltype(energy_dim * time_dim) {} action_dim; // TODO make it compile - -// clang-format on +DERIVED_DIMENSION(dynamic_viscosity, decltype(stress * length / speed)); // TODO shear stress, velocity +DERIVED_DIMENSION(kinematic_viscosity, decltype(dynamic_viscosity / mass_density)); +DERIVED_DIMENSION(surface_tension, decltype(force / length)); // TODO what is a correct equation here? +DERIVED_DIMENSION(power, decltype(force * speed)); +// TODO what about energy (potential and kinetic as separate quantities will prevent an equation for mechanical one, is +// it expected?) +DERIVED_DIMENSION(efficiency, decltype(power / power)); +DERIVED_DIMENSION(mass_flow, decltype(mass_density * speed)); // TODO velocity +DERIVED_DIMENSION(mass_flow_rate, decltype(mass_flow * area)); +DERIVED_DIMENSION(mass_change_rate, decltype(mass / time)); +DERIVED_DIMENSION(volume_flow_rate, decltype(speed * area)); // TODO velocity +// DERIVED_DIMENSION(action, decltype(energy * time)); // TODO make it compile } // namespace units::isq diff --git a/src/systems/isq/include/units/isq/space_and_time.h b/src/systems/isq/include/units/isq/space_and_time.h index 4357b630..829bf052 100644 --- a/src/systems/isq/include/units/isq/space_and_time.h +++ b/src/systems/isq/include/units/isq/space_and_time.h @@ -27,42 +27,40 @@ namespace units::isq { -// clang-format off -// inline constexpr struct length_dim : base_dimension<"L"> {} length_dim; -inline constexpr struct curvature_dim : decltype(1 / length_dim) {} curvature_dim; -inline constexpr struct area_dim : decltype(length_dim * length_dim) {} area_dim; -inline constexpr struct volume_dim : decltype(length_dim * length_dim * length_dim) {} volume_dim; -inline constexpr struct angular_measure_dim : decltype(length_dim / length_dim) {} angular_measure_dim; -inline constexpr struct angular_displacement_dim : decltype(length_dim / length_dim) {} angular_displacement_dim; -inline constexpr struct phase_angle_dim : decltype(length_dim / length_dim) {} phase_angle_dim; -inline constexpr struct solid_angular_measure_dim : decltype(area_dim / (length_dim * length_dim)) {} solid_angular_measure_dim; -// inline constexpr struct time_dim : base_dimension<"T"> {} time_dim; // TODO called duration in ISO 80000 +// inline constexpr struct length : base_dimension<"L"> {} length; +DERIVED_DIMENSION(curvature, decltype(1 / length)); +DERIVED_DIMENSION(area, decltype(length * length)); +DERIVED_DIMENSION(volume, decltype(length * length * length)); +DERIVED_DIMENSION(angular_measure, decltype(length / length)); +DERIVED_DIMENSION(angular_displacement, decltype(length / length)); +DERIVED_DIMENSION(phase_angle, decltype(length / length)); +inline constexpr struct solid_angular_measure : decltype(area / (length * length)) { +} solid_angular_measure; +// inline constexpr struct time : base_dimension<"T"> {} time; // TODO called duration in ISO 80000 // TODO there is also a velocity in ISO 80000 -inline constexpr struct speed_dim : decltype(length_dim / time_dim) {} speed_dim; -inline constexpr struct acceleration_dim : decltype(speed_dim / time_dim) {} acceleration_dim; -inline constexpr struct angular_velocity_dim : decltype(angular_displacement_dim / time_dim) {} angular_velocity_dim; -inline constexpr struct angular_acceleration_dim : decltype(angular_velocity_dim / time_dim) {} angular_acceleration_dim; -inline constexpr struct period_duration_dim : time_dim {} period_duration_dim; -inline constexpr struct time_constant_dim : time_dim {} time_constant_dim; -inline constexpr struct rotation_dim : angular_displacement_dim {} rotation_dim; -inline constexpr struct frequency_dim : decltype(1 / time_dim) {} frequency_dim; -inline constexpr struct rotational_frequency_dim : decltype(rotation_dim / time_dim) {} rotational_frequency_dim; -inline constexpr struct angular_frequency_dim : decltype(angular_measure_dim / time_dim) {} angular_frequency_dim; -inline constexpr struct wavelength_dim : length_dim {} wavelength_dim; -inline constexpr struct repetency_dim : decltype(1 / wavelength_dim) {} repetency_dim; -inline constexpr struct wave_vector_dim : decltype(1 / length_dim) {} wave_vector_dim; -inline constexpr struct angular_repetency_dim : decltype(1 / wavelength_dim) {} angular_repetency_dim; -inline constexpr struct phase_velocity_dim : decltype(angular_frequency_dim / angular_repetency_dim) {} phase_velocity_dim; -inline constexpr struct damping_coefficient_dim : decltype(1 / time_constant_dim) {} damping_coefficient_dim; -inline constexpr struct logarithmic_decrement_dim : decltype(damping_coefficient_dim * period_duration_dim) {} logarithmic_decrement_dim; -inline constexpr struct attenuation_dim : decltype(1 / length_dim) {} attenuation_dim; -inline constexpr struct phase_coefficient_dim : decltype(phase_angle_dim / length_dim) {} phase_coefficient_dim; -inline constexpr struct propagation_coefficient_dim : decltype(1 / length_dim) {} propagation_coefficient_dim; -// clang-format on +DERIVED_DIMENSION(speed, decltype(length / time)); +DERIVED_DIMENSION(acceleration, decltype(speed / time)); +DERIVED_DIMENSION(angular_velocity, decltype(angular_displacement / time)); +DERIVED_DIMENSION(angular_acceleration, decltype(angular_velocity / time)); +inline constexpr struct period_duration : time { +} period_duration; +inline constexpr struct time_constant : time { +} time_constant; +inline constexpr struct rotation : angular_displacement { +} rotation; +DERIVED_DIMENSION(frequency, decltype(1 / time)); +DERIVED_DIMENSION(rotational_frequency, decltype(rotation / time)); +DERIVED_DIMENSION(angular_frequency, decltype(angular_measure / time)); +inline constexpr struct wavelength : length { +} wavelength; +DERIVED_DIMENSION(repetency, decltype(1 / wavelength)); +DERIVED_DIMENSION(wave_vector, decltype(1 / length)); +DERIVED_DIMENSION(angular_repetency, decltype(1 / wavelength)); +DERIVED_DIMENSION(phase_velocity, decltype(angular_frequency / angular_repetency)); +DERIVED_DIMENSION(damping_coefficient, decltype(1 / time_constant)); +DERIVED_DIMENSION(logarithmic_decrement, decltype(damping_coefficient * period_duration)); +DERIVED_DIMENSION(attenuation, decltype(1 / length)); +DERIVED_DIMENSION(phase_coefficient, decltype(phase_angle / length)); +DERIVED_DIMENSION(propagation_coefficient, decltype(1 / length)); } // namespace units::isq - - -// inline constexpr struct force_dim : decltype(mass_dim * acceleration_dim) {} force_dim; -// inline constexpr struct energy_dim : decltype(force_dim * length_dim) {} energy_dim; -// inline constexpr struct power_dim : decltype(force_dim * speed_dim) {} power_dim; diff --git a/src/systems/isq/include/units/isq/thermodynamics.h b/src/systems/isq/include/units/isq/thermodynamics.h index afe0bd39..80956a3b 100644 --- a/src/systems/isq/include/units/isq/thermodynamics.h +++ b/src/systems/isq/include/units/isq/thermodynamics.h @@ -28,15 +28,12 @@ namespace units::isq { -// clang-format off -// inline constexpr struct thermodynamic_temperature_dim : base_dimension<"Θ"> {} thermodynamic_temperature_dim; +// inline constexpr struct thermodynamic_temperature : base_dimension<"Θ"> {} thermodynamic_temperature; // TODO Celsius temperature??? -// inline constexpr struct mass_density_dim : decltype(mass_dim / volume_dim) {} mass_density_dim; +// DERIVED_DIMENSION(mass_density, decltype(mass / volume)); -inline constexpr struct energy_dim : decltype(force_dim * length_dim) {} energy_dim; - -// clang-format on +DERIVED_DIMENSION(energy, decltype(force * length)); } // namespace units::isq diff --git a/src/systems/si-cgs/include/units/si/cgs/cgs.h b/src/systems/si-cgs/include/units/si/cgs/cgs.h index 4c68f3b6..4b8091f8 100644 --- a/src/systems/si-cgs/include/units/si/cgs/cgs.h +++ b/src/systems/si-cgs/include/units/si/cgs/cgs.h @@ -42,16 +42,6 @@ inline constexpr struct poise : named_unit<"P", gram / (centimetre * second)> {} inline constexpr struct stokes : named_unit<"St", square / second> {} stokes; inline constexpr struct kayser : decltype(1 / centimetre) {} kayser; -inline constexpr struct length : system_reference {} length; -inline constexpr struct mass : system_reference {} mass; -inline constexpr struct time : system_reference {} time; -inline constexpr struct speed : system_reference {} speed; -inline constexpr struct acceleration : system_reference {} acceleration; -inline constexpr struct force : system_reference {} force;inline constexpr struct energy : system_reference {} energy; -inline constexpr struct power : system_reference {} power; -inline constexpr struct dynamic_viscosity : system_reference {} dynamic_viscosity; -inline constexpr struct kinematic_viscosity : system_reference {} kinematic_viscosity; -// inline constexpr struct wavenumber : system_reference {} wavenumber; // clang-format on } // namespace units::si::cgs diff --git a/src/systems/si/CMakeLists.txt b/src/systems/si/CMakeLists.txt index eb54a1c4..4e2ed458 100644 --- a/src/systems/si/CMakeLists.txt +++ b/src/systems/si/CMakeLists.txt @@ -23,15 +23,7 @@ cmake_minimum_required(VERSION 3.19) add_units_module( - si - DEPENDENCIES mp-units::isq - HEADERS include/units/si/base_quantities.h - include/units/si/constants.h - include/units/si/mechanics.h - include/units/si/prefixes.h - include/units/si/si.h - include/units/si/space_and_time.h - include/units/si/thermodynamics.h - include/units/si/unit_symbols.h - include/units/si/units.h + si DEPENDENCIES mp-units::isq + HEADERS include/units/si/constants.h include/units/si/prefixes.h include/units/si/si.h + include/units/si/unit_symbols.h include/units/si/units.h ) diff --git a/src/systems/si/include/units/si/base_quantities.h b/src/systems/si/include/units/si/base_quantities.h deleted file mode 100644 index 91d557f5..00000000 --- a/src/systems/si/include/units/si/base_quantities.h +++ /dev/null @@ -1,43 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include -#include - -namespace units::si { - -// inline constexpr struct time : system_reference {} time; -// inline constexpr struct length : system_reference {} length; -// inline constexpr struct mass : system_reference {} mass; -inline constexpr struct electric_current : system_reference { -} electric_current; -inline constexpr struct thermodynamic_temperature : system_reference { -} thermodynamic_temperature; -inline constexpr struct amount_of_substance : system_reference { -} amount_of_substance; -inline constexpr struct luminous_intensity : system_reference { -} luminous_intensity; - -} // namespace units::si diff --git a/src/systems/si/include/units/si/constants.h b/src/systems/si/include/units/si/constants.h index 1027bf37..c9bda269 100644 --- a/src/systems/si/include/units/si/constants.h +++ b/src/systems/si/include/units/si/constants.h @@ -22,10 +22,10 @@ #pragma once +#include +#include +#include #include -#include -#include -#include #include namespace units::si { @@ -38,10 +38,10 @@ inline constexpr struct mag_speed_of_light : decltype(mag<299'792'458>) {} mag_s // clang-format on template -inline constexpr auto planck_constant = Rep{1} * (mag_planck * energy[joule] * time[second]); +inline constexpr auto planck_constant = Rep{1} * (mag_planck * isq::energy[joule] * isq::time[second]); template -inline constexpr auto speed_of_light = Rep{1} * speed[mag_speed_of_light * metre / second]; +inline constexpr auto speed_of_light = Rep{1} * isq::speed[mag_speed_of_light * metre / second]; // template // inline constexpr auto planck_constant = energy(6.62607015e-34) * time(1); @@ -75,6 +75,6 @@ inline constexpr struct mag_standard_gravity : decltype(mag -inline constexpr auto standard_gravity = Rep{1} * acceleration[mag_standard_gravity * metre / square]; +inline constexpr auto standard_gravity = Rep{1} * isq::acceleration[mag_standard_gravity * metre / square]; } // namespace units::si diff --git a/src/systems/si/include/units/si/mechanics.h b/src/systems/si/include/units/si/mechanics.h deleted file mode 100644 index e657aca7..00000000 --- a/src/systems/si/include/units/si/mechanics.h +++ /dev/null @@ -1,68 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include -#include -#include - -namespace units::si { - -// clang-format off -inline constexpr struct mass : system_reference {} mass; -inline constexpr struct mass_density : system_reference> {} mass_density; -inline constexpr struct specific_volume : system_reference / kilogram> {} specific_volume; -inline constexpr struct relative_mass_density : system_reference {} relative_mass_density; -inline constexpr struct surface_mass_density : system_reference> {} surface_mass_density; -inline constexpr struct linear_mass_density : system_reference {} linear_mass_density; -inline constexpr struct momentum : system_reference {} momentum; -inline constexpr struct force : system_reference {} force; -// inline constexpr struct weight : system_reference {} weight; -inline constexpr struct impulse : system_reference {} impulse; -inline constexpr struct angular_momentum : system_reference / second> {} angular_momentum; // TODO radian? -inline constexpr struct moment_of_inertia : system_reference> {} moment_of_inertia; -inline constexpr struct moment_of_force : system_reference {} moment_of_force; -inline constexpr struct torque : system_reference {} torque; -inline constexpr struct angular_impulse : system_reference {} angular_impulse; -inline constexpr struct pressure : system_reference {} pressure; -inline constexpr struct stress : system_reference {} stress; -inline constexpr struct normal_stress : system_reference {} normal_stress; -inline constexpr struct strain : system_reference {} strain; -inline constexpr struct poisson_number : system_reference {} poisson_number; -inline constexpr struct compressibility : system_reference {} compressibility; -inline constexpr struct second_axial_moment_of_area : system_reference * square> {} second_axial_moment_of_area; -inline constexpr struct section_modulus : system_reference> {} section_modulus; -inline constexpr struct dynamic_viscosity : system_reference {} dynamic_viscosity; -inline constexpr struct kinematic_viscosity : system_reference / second> {} kinematic_viscosity; -inline constexpr struct surface_tension : system_reference {} surface_tension; -inline constexpr struct power : system_reference {} power; -inline constexpr struct efficiency : system_reference {} efficiency; -inline constexpr struct mass_flow : system_reference * second)> {} mass_flow; -inline constexpr struct mass_flow_rate : system_reference {} mass_flow_rate; -inline constexpr struct mass_change_rate : system_reference {} mass_change_rate; -inline constexpr struct volume_flow_rate : system_reference / second> {} volume_flow_rate; -// inline constexpr struct action : system_reference {} action; // TODO make it compile -// clang-format on - -} // namespace units::si diff --git a/src/systems/si/include/units/si/si.h b/src/systems/si/include/units/si/si.h index 70878f77..e97aff6d 100644 --- a/src/systems/si/include/units/si/si.h +++ b/src/systems/si/include/units/si/si.h @@ -22,11 +22,7 @@ #pragma once -#include #include -#include #include -#include -#include #include #include diff --git a/src/systems/si/include/units/si/space_and_time.h b/src/systems/si/include/units/si/space_and_time.h deleted file mode 100644 index 697429d0..00000000 --- a/src/systems/si/include/units/si/space_and_time.h +++ /dev/null @@ -1,64 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include -#include - -namespace units::si { - -// clang-format off -inline constexpr struct length : system_reference {} length; -inline constexpr struct curvature : system_reference {} curvature; -inline constexpr struct area : system_reference> {} area; -inline constexpr struct volume : system_reference> {} volume; -inline constexpr struct angular_measure : system_reference {} angular_measure; -inline constexpr struct angular_displacement : system_reference {} angular_displacement; -inline constexpr struct phase_angle : system_reference {} phase_angle; -inline constexpr struct solid_angular_measure : system_reference {} solid_angular_measure; -inline constexpr struct time : system_reference {} time; // TODO called duration in ISO 80000 -// TODO there is also a velocity in ISO 80000 -inline constexpr struct speed : system_reference {} speed; -inline constexpr struct acceleration : system_reference> {} acceleration; -inline constexpr struct angular_velocity : system_reference {} angular_velocity; -inline constexpr struct angular_acceleration : system_reference> {} angular_acceleration; -inline constexpr struct period_duration : system_reference {} period_duration; -inline constexpr struct time_constant : system_reference {} time_constant; -inline constexpr struct rotation : system_reference {} rotation; -inline constexpr struct frequency : system_reference {} frequency; -inline constexpr struct rotational_frequency : system_reference {} rotational_frequency; -inline constexpr struct angular_frequency : system_reference {} angular_frequency; -inline constexpr struct wavelength : system_reference {} wavelength; -inline constexpr struct repetency : system_reference {} repetency; -inline constexpr struct wave_vector : system_reference {} wave_vector; -inline constexpr struct angular_repetency : system_reference {} angular_repetency; -inline constexpr struct phase_velocity : system_reference {} phase_velocity; -inline constexpr struct damping_coefficient : system_reference {} damping_coefficient; -inline constexpr struct logarithmic_decrement : system_reference {} logarithmic_decrement; -inline constexpr struct attenuation : system_reference {} attenuation; -inline constexpr struct phase_coefficient : system_reference {} phase_coefficient; -inline constexpr struct propagation_coefficient : system_reference {} propagation_coefficient; -// clang-format on - -} // namespace units::si diff --git a/src/systems/si/include/units/si/thermodynamics.h b/src/systems/si/include/units/si/thermodynamics.h deleted file mode 100644 index 33538eb9..00000000 --- a/src/systems/si/include/units/si/thermodynamics.h +++ /dev/null @@ -1,39 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -// #include -#include -#include -#include - -namespace units::si { - -// inline constexpr struct thermodynamic_temperature : system_reference {} -// thermodynamic_temperature; - -inline constexpr struct energy : system_reference { -} energy; - -} // namespace units::si diff --git a/src/systems/si/include/units/si/units.h b/src/systems/si/include/units/si/units.h index 26b46db8..05b08a4b 100644 --- a/src/systems/si/include/units/si/units.h +++ b/src/systems/si/include/units/si/units.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include @@ -29,14 +30,14 @@ namespace units::si { // clang-format off // base units -inline constexpr struct second : named_unit<"s"> {} second; -inline constexpr struct metre : named_unit<"m"> {} metre; -inline constexpr struct gram : named_unit<"g"> {} gram; +inline constexpr struct second : named_unit<"s", isq::time> {} second; +inline constexpr struct metre : named_unit<"m", isq::length> {} metre; +inline constexpr struct gram : named_unit<"g", isq::mass> {} gram; inline constexpr struct kilogram : decltype(kilo) {} kilogram; -inline constexpr struct ampere : named_unit<"A"> {} ampere; -inline constexpr struct kelvin : named_unit<"K"> {} kelvin; -inline constexpr struct mole : named_unit<"mol"> {} mole; -inline constexpr struct candela : named_unit<"cd"> {} candela; +inline constexpr struct ampere : named_unit<"A", isq::electric_current> {} ampere; +inline constexpr struct kelvin : named_unit<"K", isq::thermodynamic_temperature> {} kelvin; +inline constexpr struct mole : named_unit<"mol", isq::amount_of_substance> {} mole; +inline constexpr struct candela : named_unit<"cd", isq::luminous_intensity> {} candela; // derived named units inline constexpr struct radian : named_unit<"rad", metre / metre> {} radian; @@ -90,7 +91,7 @@ inline constexpr struct electronvolt : named_unit<"eV", mag -inline constexpr bool unit_can_be_prefixed = false; +inline constexpr bool unit_can_be_prefixed = false; // TODO Is it true? template<> inline constexpr bool unit_can_be_prefixed = false; template<> diff --git a/test/unit_test/static/CMakeLists.txt b/test/unit_test/static/CMakeLists.txt index 587f824d..2dcd38bc 100644 --- a/test/unit_test/static/CMakeLists.txt +++ b/test/unit_test/static/CMakeLists.txt @@ -35,7 +35,6 @@ cmake_minimum_required(VERSION 3.2) add_library( unit_tests_static dimension_test.cpp - # angle_test.cpp # cgs_test.cpp # chrono_test.cpp @@ -49,7 +48,6 @@ add_library( # iec80000_test.cpp # kind_test.cpp magnitude_test.cpp - # math_test.cpp # point_origin_test.cpp # prime_test.cpp @@ -62,7 +60,6 @@ add_library( # symbol_text_test.cpp type_list_test.cpp unit_test.cpp - # us_test.cpp ) diff --git a/test/unit_test/static/dimension_test.cpp b/test/unit_test/static/dimension_test.cpp index 25cb5c3d..12088ab5 100644 --- a/test/unit_test/static/dimension_test.cpp +++ b/test/unit_test/static/dimension_test.cpp @@ -20,206 +20,199 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include "test_tools.h" #include namespace { using namespace units; -template -inline constexpr bool is_of_type = std::is_same_v, T>; - -using one_dim_ = struct one_dim; +using dimensionless_ = struct dimensionless; // clang-format off -inline constexpr struct length_dim_ : base_dimension<"L"> {} length_dim; -inline constexpr struct time_dim_ : base_dimension<"T"> {} time_dim; -inline constexpr struct mass_dim_ : base_dimension<"M"> {} mass_dim; +BASE_DIMENSION_(length, "L"); +BASE_DIMENSION_(time, "T"); +BASE_DIMENSION_(mass, "M"); -inline constexpr struct frequency_dim_ : decltype(1 / time_dim) {} frequency_dim; -inline constexpr struct action_dim_ : decltype(1 / time_dim) {} action_dim; -inline constexpr struct area_dim_ : decltype(length_dim * length_dim) {} area_dim; -inline constexpr struct volume_dim_ : decltype(area_dim * length_dim) {} volume_dim; -inline constexpr struct speed_dim_ : decltype(length_dim / time_dim) {} speed_dim; -inline constexpr struct velocity_dim_ : speed_dim_ {} velocity_dim; -inline constexpr struct acceleration_dim_ : decltype(speed_dim / time_dim) {} acceleration_dim; -inline constexpr struct force_dim_ : decltype(mass_dim * acceleration_dim) {} force_dim; -inline constexpr struct moment_of_force_dim_ : decltype(length_dim * force_dim) {} moment_of_force_dim; -inline constexpr struct torque_dim_ : decltype(moment_of_force_dim) {} torque_dim; -inline constexpr struct pressure_dim_ : decltype(force_dim / area_dim) {} pressure_dim; -inline constexpr struct stress_dim_ : decltype(pressure_dim) {} stress_dim; -inline constexpr struct strain_dim_ : decltype(stress_dim / stress_dim) {} strain_dim; -inline constexpr struct power_dim_ : decltype(force_dim * speed_dim) {} power_dim; -inline constexpr struct efficiency_dim_ : decltype(power_dim / power_dim) {} efficiency_dim; -inline constexpr struct energy_dim_ : decltype(force_dim * length_dim) {} energy_dim; +DERIVED_DIMENSION_(frequency, decltype(1 / time)); +DERIVED_DIMENSION_(action, decltype(1 / time)); +DERIVED_DIMENSION_(area, decltype(length * length)); +DERIVED_DIMENSION_(volume, decltype(area * length)); +DERIVED_DIMENSION_(speed, decltype(length / time)); +inline constexpr struct velocity_ : speed_ {} velocity; +DERIVED_DIMENSION_(acceleration, decltype(speed / time)); +DERIVED_DIMENSION_(force, decltype(mass * acceleration)); +DERIVED_DIMENSION_(moment_of_force, decltype(length * force)); +DERIVED_DIMENSION_(torque, decltype(moment_of_force)); +DERIVED_DIMENSION_(pressure, decltype(force / area)); +DERIVED_DIMENSION_(stress, decltype(pressure)); +DERIVED_DIMENSION_(strain, decltype(stress / stress)); +DERIVED_DIMENSION_(power, decltype(force * speed)); +DERIVED_DIMENSION_(efficiency, decltype(power / power)); +DERIVED_DIMENSION_(energy, decltype(force * length)); // clang-format on // concepts verification -static_assert(BaseDimension); -static_assert(!BaseDimension); -static_assert(!DerivedDimension); -static_assert(DerivedDimension); -static_assert(Dimension); -static_assert(Dimension); +static_assert(BaseDimension); +static_assert(!BaseDimension); +static_assert(!DerivedDimension); +static_assert(DerivedDimension); +static_assert(Dimension); +static_assert(Dimension); -static_assert(DerivedDimension); -static_assert(DerivedDimension); // one_dim -static_assert(BaseDimension); // length_dim +static_assert(DerivedDimension); +static_assert(DerivedDimension); // dimensionless +static_assert(BaseDimension); // length // derived dimension expression template syntax verification -static_assert(is_of_type<1 / time_dim, derived_dimension>>); -static_assert(is_of_type<1 / (1 / time_dim), time_dim_>); +static_assert(is_of_type<1 / time, derived_dimension>>); +static_assert(is_of_type<1 / (1 / time), time_>); -static_assert(is_of_type); -static_assert(is_of_type); -static_assert(is_of_type>>); -static_assert(is_of_type<1 / time_dim * one_dim, derived_dimension>>); +static_assert(is_of_type); +static_assert(is_of_type