diff --git a/CHANGELOG.md b/CHANGELOG.md index d94e3d6..38cf61d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,28 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.2.0] - 2024-03-16 + +### Changed + +- Powers are now rational numbers and not floating point values. + +### Added + +- New coherent unit `scalar` that can be used in binary operations with units. +- New constructor `Coherent_unit(TU_TYPE)` so that a coherent unit can be created with value. +- New prefixes `quecto`, `ronto`, `ronna`, `quetta`. + +### Fixed + +- Ambiguities and typos in documentation. + +## [0.1.0] - 2022-04-19 + +### Added + +- Core functionality of **TU** diff --git a/CMakeLists.txt b/CMakeLists.txt index b2d2071..d6228ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.12) -project(TU VERSION 0.1.0 LANGUAGES CXX) +project(TU VERSION 0.2.0 LANGUAGES CXX) enable_testing() add_subdirectory(typesafe_units) diff --git a/README.md b/README.md index 3f258a6..e7140c0 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,10 @@ Unit c = s * a; std::cout << c.value << std::endl; // prints 5e-08 ``` -If you need a non-SI unit you define it by declaring a simple struct. This is how you would define the unit -`degree_Fahrenheit`: +If you need a non-SI unit you define it by declaring a Non_coherent_unit. This is how you would define the unit `degree_Fahrenheit`: ```c++ - struct degree_Fahrenheit : Non_coherent_unit<1.0f / 1.8f, -32.0f, degree_Celsius> { - using Non_coherent_unit<1.0f / 1.8f, -32.0f, degree_Celsius>::Base; - }; +using degree_Fahrenheit = Non_coherent_unit<1.0f / 1.8f, -32.0f, degree_Celsius>; ``` You can use the new unit like any other unit already defined in TU: @@ -71,9 +68,7 @@ target_compile_definitions(my_target PRIVATE TU_TYPE=double) ## Requirements -TU requires a c++20 compliant compiler. Specifically TU utilizes float non-type template arguments. - -For the test suite that comes with TU to work, your system needs to have support for ANSI escape sequences since the output uses colours. This should work on fairly recent Windows 10 system, linux and macOS. It might be a problem on Windows 7 though. If you find that this is a showstopper for you please let us know. If enough people run TU on systems that does not have support for ANSI escape sequences, we will remove it. +TU requires a c++20 compliant compiler. For the test suite that comes with TU to work, your system needs to have support for ANSI escape sequences since the output uses colours. This should work on fairly recent Windows 10 system, linux and macOS. It might be a problem on Windows 7 though. If you find that this is a showstopper for you please let us know. If enough people run TU on systems that does not have support for ANSI escape sequences, we will remove it. ## Tested compilers @@ -119,14 +114,14 @@ TU comes with its own test suite. It does not rely on any external testing tool. The following instruction assumes that you do an out of source build in a directory under the repository root. ```bat -cmake .. -G -cmake --build . --config +> cmake .. -G +> cmake --build . --config ``` Run the test suite -``` -ctest -V +```bat +> ctest -V ``` The test suite test TU for both float and double as underlying datatype. @@ -135,55 +130,97 @@ The test suite test TU for both float and double as underlying datatype. The aim of TU is to be -* compliant to definitions and guides of official bodies. For SI units, TU aims for compliance with the definitions issued by Bureau International des Poids et Mesures (BIPM). See [link to bimp.org](https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf) for details. +* compliant to definitions and guides of official bodies. For SI units, TU aims for compliance with the definitions issued by Bureau International des Poids et Mesures (BIPM). See [bimp.org](https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf) for details. * (type)safe * easy to use * light weight ## License -TU is released under the MIT license. https://mit-license.org/ +TU is released under the [MIT](https://mit-license.org/) license. ## Detailed description +### Spelling + +TU uses official spelling of units. Therefore TU uses `litre` and `metre` and not *liter* and *meter*. + ### Types The intrinsic data type used by TU is defined in the preprocessor macro `TU_TYPE`. -`TU_TYPE` can be `float` or `double`. All values and floating point template argumets will have the type defined by `TU_TYPE`. +`TU_TYPE` can be `float` or `double`. All values will have the type defined by `TU_TYPE`. ### Namespaces + The main namespace of TU is `tu`. -Functionality inside `tu` that is located in the namespace `internal` is not public and should only be used implicitly by public classes and methods. +Functionality inside `tu` that is located in the namespace `internal` is not public and should only be used implicitly through public classes and methods. ### Classes and structs -#### s, m, kg, A, K, mol, cd +The TU unit system is built on five structs: `Base_unit`, `Coherent_unit`, `Non_coherent_unit`, `Unit` and the enum struct `prefix`. -These are the base units with floating point template arguments that determins the power of the base unit. -The base units are used to build `Coherent_unit`s +The illustration below shows how the different structs are used to create other structs. Structs at lower level uses structs on higher level in their construction. -The definition of each base unit looks as follows where the unit is denoted `X`. +``` +prefix Base_unit +| | +| Coherent_unit +| | | +| | Non_coherent_unit +| | | +| | Non_coherent_unit +| | | +|--------Unit +``` + +With words the above would be written: + +* `Coherent_unit` is built from `Base_unit`(s) +* `Non_coherent_unit` is built from a `Coherent_unit` or another `Non_coherent_unit` +* `Unit` is built from a `prefix` and a `Coherent_unit` or a `Non_coherent_unit`. + +The main entity that a typical user of TU will interact with is the `Unit` struct. When extending the unit system, interaction with other structs is required. At some occasions interaction with `Coherent_unit`s is necessary. + +#### Base_unit + +Base units are the smallest building blocks in the types system. These define powers of the seven basic units `s`, `m`, `kg`, `A`, `K`, `mol` and `cd`. Base units are used to build up `Coherent_unit`s. + +The definition of base units are done through inheritance of the `Base_unit` struct and looks as follows where the base unit is denoted `X`. ```c++ -template +template struct X : internal::Base_unit

{}; ``` +The definition of `s` (second) to some power `p` then looks as -The base unit `per_second` can be declared through +```c++ +template +struct s : internal::Base_unit

{}; +``` + +where Ratio is of type std:ratio + +and a base unit `per_second` can be declared through ```c++ -s<(TU_TYPE)-1.0f>; +s; ``` #### Coherent_unit -The `Coherent_unit` struct represents a unit that is a multiple of all base units: s, m, kg, A, K, mol and cd. +The `Coherent_unit` struct represents a unit that is a multiple of all base units: s, m, kg, A, K, mol and cd with individual powers. A specific coherent unit should be defined by inheriting from a `Coherent_unit` The specific coherent unit `newton` is defined as ```c++ -struct newton: Coherent_unit, m<(TU_TYPE)1.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; +using newton = Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` i.e. it has the unit `kg m / s^2` @@ -193,39 +230,38 @@ Note that computations using seconds should use the `Coherent_unit` `second` and `second` is defined as ```c++ -struct second: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; +using second = Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` + All base units are defined as `Coherent_unit`s in similar fashion. #### Non_coherent_unit A `Non_coherent_unit` is a unit that is scaled or shifted relative to a base unit. The value of the `Non_coherent_unit` is related to the value of the base unit through `v = a * b + c` where `v` is the value of the `Non_coherent_unit`, `b` is the value of the base unit. `a` and `c` are the scaling and shift respectively. -Example of `Non_coherent_unit`s are `minute`, `hour` and `degree_Celcius`. +Examples of `Non_coherent_unit`s are `minute`, `hour` and `degree_Celcius`. A `Non_coherent_unit` is a templated struct that has the scaling factor, the shift and the base unit as template parameters. `minute` and `hour` are defined by ```c++ -struct minute : Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second> { - using Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second>::Base; -}; +using minute = Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second>; -struct hour : Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute> { - using Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute>::Base; -}; +struct hour = Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute>; ``` `degree_Celsius` is defined by ```c++ -struct degree_Celsius : Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin> { - using Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin>::Base; -}; +struct degree_Celsius = Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin>; ``` -The `using` statement is of internal concern only. If new `Non_coherent_unit`s are created, just follow the pattern. - #### Unit The `Unit` is the intended public unit type. @@ -263,6 +299,8 @@ std::cout << ms.value << " " << mi.value << std::endl; // prints 5.0 8.3333e-5 The following prefixes are defined and can be used when creating `Unit`s. +* quecto = 10-30 +* ronto = 10-27 * yocto = 10-24 * zepto = 10-21 * atto = 10-18 @@ -284,6 +322,8 @@ The following prefixes are defined and can be used when creating `Unit`s. * exa = 1018 * zetta = 1021 * yotta = 1024 +* ronna = 1027 +* quetta = 1030 ### Functions @@ -311,7 +351,7 @@ std::cout << tu::convert_to(m).value << std::endl; // prin ``` ### Operators -#### + - +#### + - TU supports the binary operators `+` and `-` (addition and subtraction) on units. Conversions are handled under the hood of TU. @@ -333,14 +373,20 @@ std::cout << cu.base_value << std::endl; // prints 3900.0 This is because TU does not know what `Unit` to construct from the operation. TU falls back on the fundamental `Coherent_unit`s and `cu` will be of type ```c++ -Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>; +Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` Note also that `Coherent_unit` does not have a `value` member but only a `base_value` If we would like a specific `Unit` representation of the operation, we have to explicitly state the `Unit` as in the first example and the result of the operation will be used to construct the desired `Unit`. -Applying the `+` and `-` operators on `Unit`s that don't have the same underlying `Coherent_unit` will result in compilation failure e.g. it is not possible to add to variables of type `newton` and `second`. +Applying the `+` and `-` operators on `Unit`s that don't have the same underlying `Coherent_unit` will result in compilation failure e.g. it is not possible to add two variables of type `newton` and `second`. #### \* / @@ -365,7 +411,13 @@ std::cout << cu.base_value << std::endl; // prints 5e-08 This is because TU does not know what `Unit` to construct from the operation. TU falls back on the fundamental `Coherent_units` and `cu` will be of type ```c++ -Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>; +Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` Note also that `Coherent_unit` does not have a `value` member but only a `base_value` @@ -391,21 +443,27 @@ TU implements a `pow` operator for units. ```c++ Unit me(5.0f); -auto ch = pow<2.0f>(me); +auto ch = pow>(me); std::cout << ch.base_value << std::endl; // prints 2.5 * 10^-5 ``` `ch` will be of type ```c++ -Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>; +Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` To construct a `Unit` directly we could do ```c++ Unit me(5.0f); -Unit m2 = pow<2.0f>(me); +Unit m2 = pow>(me); std::cout << m2.value << std::endl; // prints 2.5 * 10^-2 ``` @@ -414,7 +472,7 @@ Note that `Unit` means 10-3m2 To the unit (mm)2 is equivalent to `Unit` -Note that the power is not restricted to integers. +Note that the power is restricted to std::ratio. #### sqrt @@ -426,21 +484,28 @@ sqrt(unit). is equivalent to ```c++ -pow<0.5>(unit). +pow>(unit). ``` -Not that since TU uses floating point powers, it is not guaranteed that applying first `pow<2.0>` and the `sqrt` on a unit would yield the exact unit back. - #### unop TU supports unary operations on scalar units i.e. units where all basic unit powers are `0`. Examples of scalar units is `radian` and `degree`. `unop` is a template function that applies any unary function that takes a TU_TYPE -and returns a TU_TYPE to the underlying value of the unit if it is a scalar unit. The function returns a scalar Coherent_unit initialized with the value of the performed operation. This makes it possible to operate with any unary function (subjected to the restrictions above) from the standard library on a Unit or Coherent_unit. unop can take both unary functions and lambda expressions as template parameter. +and returns a TU_TYPE to the underlying **base_value** of the unit if it is a scalar unit. The function returns a scalar Coherent_unit initialized with the value of the performed operation. This makes it possible to operate with any unary function (subjected to the restrictions above) from the standard library on a Unit or Coherent_unit. unop can take both unary functions and lambda expressions as template parameter. ```c++ -Unit angle(90); -std::cout << unop(angle).base_value; // prints 1 +Unit angle_d(90); +std::cout << unop(angle_d).base_value; // prints 1 + +Unit angle_r(PI); +std::cout << unop(angle_r).base_value; // prints 1 + +constexpr auto lambda = [](TU_TYPE v) { + return v + (TU_TYPE)1.0; +}; + +std::cout << unop(angle_d).base_value; // prints 2.5708 i.e. PI/2.0 + 1.0 ``` Note that `unop` operates on the `base_value` on a unit. In the case of `degree` the base unit is `radian` (90 degrees == pi/2 radians) and the `std::sin` function yields the correct result. @@ -488,8 +553,7 @@ Note that `unop` operates on the `base_value` on a unit. In the case of `degree` * metre_cubed * metre_squared -### Non coherent units - +### Non-coherent units #### Time diff --git a/TUConfigVersion.cmake b/TUConfigVersion.cmake index abaed05..044f151 100644 --- a/TUConfigVersion.cmake +++ b/TUConfigVersion.cmake @@ -9,16 +9,52 @@ # The variable CVF_VERSION must be set before calling configure_file(). -set(PACKAGE_VERSION "0.1.0") +if (PACKAGE_FIND_VERSION_RANGE) + message(AUTHOR_WARNING + "`find_package()` specify a version range but the version strategy " + "(ExactVersion) of the module `${PACKAGE_FIND_NAME}` is incompatible " + "with this request. Only the lower endpoint of the range will be used.") +endif() + +set(PACKAGE_VERSION "0.2.0") + +if("0.2.0" MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") # strip the tweak version + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}") + set(CVF_VERSION_PATCH "${CMAKE_MATCH_3}") -if("0.1.0" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\.") # strip the tweak version - set(CVF_VERSION_NO_TWEAK "${CMAKE_MATCH_1}") + if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}") + endif() + if(NOT CVF_VERSION_MINOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MINOR "${CVF_VERSION_MINOR}") + endif() + if(NOT CVF_VERSION_PATCH VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_PATCH "${CVF_VERSION_PATCH}") + endif() + + set(CVF_VERSION_NO_TWEAK "${CVF_VERSION_MAJOR}.${CVF_VERSION_MINOR}.${CVF_VERSION_PATCH}") else() - set(CVF_VERSION_NO_TWEAK "0.1.0") + set(CVF_VERSION_NO_TWEAK "0.2.0") endif() -if(PACKAGE_FIND_VERSION MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\.") # strip the tweak version - set(REQUESTED_VERSION_NO_TWEAK "${CMAKE_MATCH_1}") +if(PACKAGE_FIND_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") # strip the tweak version + set(REQUESTED_VERSION_MAJOR "${CMAKE_MATCH_1}") + set(REQUESTED_VERSION_MINOR "${CMAKE_MATCH_2}") + set(REQUESTED_VERSION_PATCH "${CMAKE_MATCH_3}") + + if(NOT REQUESTED_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" REQUESTED_VERSION_MAJOR "${REQUESTED_VERSION_MAJOR}") + endif() + if(NOT REQUESTED_VERSION_MINOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" REQUESTED_VERSION_MINOR "${REQUESTED_VERSION_MINOR}") + endif() + if(NOT REQUESTED_VERSION_PATCH VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" REQUESTED_VERSION_PATCH "${REQUESTED_VERSION_PATCH}") + endif() + + set(REQUESTED_VERSION_NO_TWEAK + "${REQUESTED_VERSION_MAJOR}.${REQUESTED_VERSION_MINOR}.${REQUESTED_VERSION_PATCH}") else() set(REQUESTED_VERSION_NO_TWEAK "${PACKAGE_FIND_VERSION}") endif() @@ -34,11 +70,6 @@ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) endif() -# if the installed project requested no architecture check, don't perform the check -if("FALSE") - return() -endif() - # if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") return() diff --git a/test/test.cpp b/test/test.cpp index 74b50ae..9bb3093 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -169,19 +169,30 @@ int main() { } ); + Test<"is_ratio">( + [](T &t) { + t.assert_true(is_ratio>::value, __LINE__); + t.assert_false(is_ratio::value, __LINE__); + t.assert_true(is_ratio_v>, __LINE__); + t.assert_false(is_ratio_v, __LINE__); + } + ); + Test<"Coherent_unit_base">( [](T &t) { TU_TYPE val = 3.5; - - auto c1 = Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0>(val); + auto c1 = Coherent_unit_base, std::ratio<2>>(val); t.template assert>(val, c1.base_value, __LINE__); - auto c2 = Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0>(c1); + auto c2 = Coherent_unit_base, std::ratio<2>>(c1); t.template assert>(val, c2.base_value , __LINE__); + auto c3 = Coherent_unit_base, std::ratio<2>>(std::move(c2)); + t.template assert>(val, c3.base_value , __LINE__); + Unit f(val); - Coherent_unit_base<(TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0> c3 = Coherent_unit_base(f); - t.template assert>((val * 1.0e-3f - (TU_TYPE)32.0)/1.8f + (TU_TYPE)273.15, c3.base_value , __LINE__); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>> c4 = Coherent_unit_base(f); + t.template assert>((val * 1.0e-3f - (TU_TYPE)32.0)/1.8f + (TU_TYPE)273.15, c4.base_value , __LINE__); } ); @@ -212,9 +223,9 @@ int main() { Test<"create_coherent_unit">( [](T &t){ - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0, (TU_TYPE)3.0, (TU_TYPE)4.0, (TU_TYPE)5.0, (TU_TYPE)6.0, (TU_TYPE)7.0> cub; + Coherent_unit_base, std::ratio<2>, std::ratio<3>, std::ratio<4>, std::ratio<5>, std::ratio<6>, std::ratio<7>> cub; auto cu = internal::create_coherent_unit(cub); - t.assert_true(std::is_same, m<(TU_TYPE)2.0>, kg<(TU_TYPE)3.0>, A<(TU_TYPE)4.0>, K<(TU_TYPE)5.0>, mol<(TU_TYPE)6.0>, cd<(TU_TYPE)7.0>>>::value, __LINE__); + t.assert_true(std::is_same>, m>, kg>, A>, K>, mol>, cd>>>::value, __LINE__); } ); @@ -246,11 +257,11 @@ int main() { Test<"is_scalar">( [](T &t){ TU_TYPE val = 0.0; - auto not_scalar = Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0>(val); - auto not_scalar2 = Coherent_unit_base<(TU_TYPE)0.0, (TU_TYPE)2.0>(val); - auto not_scalar3 = Coherent_unit_base<(TU_TYPE)1.0>(val); - auto scalar = Coherent_unit_base<(TU_TYPE)0.0, (TU_TYPE)0.0>(val); - auto scalar2 = Coherent_unit_base<(TU_TYPE)0.0>(val); + auto not_scalar = Coherent_unit_base, std::ratio<2>>(val); + auto not_scalar2 = Coherent_unit_base, std::ratio<2>>(val); + auto not_scalar3 = Coherent_unit_base>(val); + auto scalar = Coherent_unit_base, std::ratio<0>>(val); + auto scalar2 = Coherent_unit_base>(val); t.assert_false(not_scalar.is_scalar(), __LINE__); t.assert_false(not_scalar2.is_scalar(), __LINE__); @@ -289,8 +300,8 @@ int main() { auto value2 = 20000.0f; //Unit s1(value1); //Unit s2(value2); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> s1(value1); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> s2(value2); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> s1(value1); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> s2(value2); t.assert_true(s1 < s2, __LINE__); t.assert_false(s1 >= s2, __LINE__); @@ -315,7 +326,7 @@ int main() { Unit s1(value1); Unit s2(value2); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> s12 = s1 + s2; + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> s12 = s1 + s2; t.template assert>((TU_TYPE)30.0e-3f, s12.base_value, __LINE__); } ); @@ -327,10 +338,8 @@ int main() { Unit s1(value1); Unit s2(value2); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> s12 = s1 - s2; + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> s12 = s1 - s2; t.template assert>(-(TU_TYPE)10.0e-3f, s12.base_value, __LINE__); - - auto s3 = s12 + s12; } ); @@ -340,7 +349,7 @@ int main() { TU_TYPE value2 = 20.0; Unit s1(value1); Unit a1(value2); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> sa = s1 * a1; + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> sa = s1 * a1; t.template assert>(sa.base_value, value1 * value2 * (TU_TYPE)1.0e-6f, __LINE__); } ); @@ -352,7 +361,7 @@ int main() { Unit s1(value1); Unit a1(value2); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)-1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> sa = s1 / a1; + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> sa = s1 / a1; t.template assert>(sa.base_value, value1 / value2, __LINE__); } ); @@ -361,16 +370,16 @@ int main() { [](T &t){ TU_TYPE value1 = 10.0; TU_TYPE value2 = 20.0; - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> s1(value1); - Coherent_unit_base<(TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> a1(value2); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> s1(value1); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>, std::ratio<0>> a1(value2); - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> sa = s1 * a1; + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>, std::ratio<0>> sa = s1 * a1; t.template assert>(sa.base_value, value1 * value2, __LINE__); auto s2 = internal::create_coherent_unit(s1); auto a2 = internal::create_coherent_unit(a1); - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> sa2 = s2 * a2; + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>, std::ratio<0>> sa2 = s2 * a2; t.template assert>(sa2.base_value, value1 * value2, __LINE__); } ); @@ -379,66 +388,106 @@ int main() { [](T &t){ auto value1 = (TU_TYPE)10.0f; auto value2 = (TU_TYPE)20.0f; - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> s1(value1); - Coherent_unit_base<(TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> a1(value2); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> s1(value1); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>, std::ratio<0>> a1(value2); - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)-1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> sa = s1 / a1; + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<-1>, std::ratio<0>, std::ratio<0>, std::ratio<0>> sa = s1 / a1; t.template assert>(sa.base_value, value1 / value2, __LINE__); auto s2 = internal::create_coherent_unit(s1); auto a2 = internal::create_coherent_unit(a1); - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)-1.0, (TU_TYPE)0.0, (TU_TYPE)0.0, (TU_TYPE)0.0> sa2 = s2 / a2; + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<-1>, std::ratio<0>, std::ratio<0>, std::ratio<0>> sa2 = s2 / a2; t.template assert>(sa2.base_value, value1 / value2, __LINE__); } ); + Test<"Coherent_unit and Coherent_unit_base binary operator: +">( + [](T &t){ + auto value1 = (TU_TYPE)10.0f; + auto value2 = (TU_TYPE)20.0f; + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> s1(value1); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> a1(value2); + + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> sa = s1 + a1; + t.template assert>(sa.base_value, value1 + value2, __LINE__); + + auto s2 = internal::create_coherent_unit(s1); + auto a2 = internal::create_coherent_unit(a1); + + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> sa2 = s2 + a2; + t.template assert>(sa2.base_value, value1 + value2, __LINE__); + } + ); + + Test<"Coherent_unit and Coherent_unit_base binary operator: -">( + [](T &t){ + auto value1 = (TU_TYPE)10.0f; + auto value2 = (TU_TYPE)20.0f; + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> s1(value1); + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> a1(value2); + + Coherent_unit_base, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> sa = s1 - a1; + t.template assert>(sa.base_value, value1 - value2, __LINE__); + + auto s2 = internal::create_coherent_unit(s1); + auto a2 = internal::create_coherent_unit(a1); + + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> sa2 = s2 - a2; + t.template assert>(sa2.base_value, value1 - value2, __LINE__); + } + ); + Test<"binary_op_args">( [](T ){ { - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0, (TU_TYPE)3.0, (TU_TYPE)4.0, (TU_TYPE)5.0, (TU_TYPE)6.0, (TU_TYPE)7.0> l(2); - Coherent_unit_base<(TU_TYPE)6.0, (TU_TYPE)5.0, (TU_TYPE)4.0, (TU_TYPE)3.0, (TU_TYPE)2.0, (TU_TYPE)1.0, (TU_TYPE)0.0> r(3); + Coherent_unit_base, std::ratio<2>, std::ratio<3>, std::ratio<4>, std::ratio<5>, std::ratio<6>, std::ratio<7>> l(2); + Coherent_unit_base, std::ratio<5>, std::ratio<4>, std::ratio<3>, std::ratio<2>, std::ratio<1>, std::ratio<0>> r(3); Coherent_unit_base<> lr; - Coherent_unit_base<(TU_TYPE)7.0, (TU_TYPE)7.0, (TU_TYPE)7.0, (TU_TYPE)7.0, (TU_TYPE)7.0, (TU_TYPE)7.0, (TU_TYPE)7.0> l_plus_r = binary_op_args(l, r, lr, std::plus()); - Coherent_unit, m<(TU_TYPE)7.0>, kg<(TU_TYPE)7.0>, A<(TU_TYPE)7.0>, K<(TU_TYPE)7.0>, mol<(TU_TYPE)7.0>, cd<(TU_TYPE)7.0>> l_plus_r_c = binary_op_args(l, r, lr, std::plus()); + Coherent_unit_base, std::ratio<7>, std::ratio<7>, std::ratio<7>, std::ratio<7>, std::ratio<7>, std::ratio<7>> l_plus_r = binary_op_args(l, r, lr, Plus()); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> l_plus_r_c = binary_op_args(l, r, lr, Plus()); } } ); Test<"binary_op_args_num">( [](T ) { - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0, (TU_TYPE)3.0, (TU_TYPE)4.0, (TU_TYPE)5.0, (TU_TYPE)6.0, (TU_TYPE)7.0> l; + Coherent_unit_base, std::ratio<2>, std::ratio<3>, std::ratio<4>, std::ratio<5>, std::ratio<6>, std::ratio<7>> l; Coherent_unit_base<> empty; - Coherent_unit_base<(TU_TYPE)2.0, (TU_TYPE)4.0, (TU_TYPE)6.0, (TU_TYPE)8.0, (TU_TYPE)10.0, (TU_TYPE)12.0, (TU_TYPE)14.0> r = binary_op_args_num(l, powexp<(TU_TYPE)2.0>(), empty, std::multiplies()); - Coherent_unit, m<(TU_TYPE)4.0>, kg<(TU_TYPE)6.0>, A<(TU_TYPE)8.0>, K<(TU_TYPE)10.0>, mol<(TU_TYPE)12.0>, cd<(TU_TYPE)14.0>> r2 = binary_op_args_num(l, powexp<(TU_TYPE)2.0>(), empty, std::multiplies()); + Coherent_unit_base, std::ratio<4>, std::ratio<6>, std::ratio<8>, std::ratio<10>, std::ratio<12>, std::ratio<14>> r = binary_op_args_num(l, std::ratio<2>(), empty, Multiply()); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> r2 = binary_op_args_num(l, std::ratio<2>(), empty, Multiply()); } ); Test<"pow Coherent_unit_base">( [](T &t) { TU_TYPE value = 3.0; - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0, (TU_TYPE)3.0, (TU_TYPE)4.0, (TU_TYPE)5.0, (TU_TYPE)6.0, (TU_TYPE)7.0> r(value); - Coherent_unit_base<(TU_TYPE)2.0, (TU_TYPE)4.0, (TU_TYPE)6.0, (TU_TYPE)8.0, (TU_TYPE)10.0, (TU_TYPE)12.0, (TU_TYPE)14.0> l = pow<(TU_TYPE)2.0>(r); + Coherent_unit_base, std::ratio<2>, std::ratio<3>, std::ratio<4>, std::ratio<5>, std::ratio<6>, std::ratio<7>> r(value); + Coherent_unit_base, std::ratio<4>, std::ratio<6>, std::ratio<8>, std::ratio<10>, std::ratio<12>, std::ratio<14>> l = pow>(r); t.template assert>((TU_TYPE)pow(value, (TU_TYPE)2.0f), l.base_value, __LINE__); - Coherent_unit, m<(TU_TYPE)4.0>, kg<(TU_TYPE)6.0>, A<(TU_TYPE)8.0>, K<(TU_TYPE)10.0>, mol<(TU_TYPE)12.0>, cd<(TU_TYPE)14.0>> a = pow<(TU_TYPE)2.0>(r); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> a = pow>(r); } ); - Test<"pow Unit">( + Test<"pow Unit">( [](T &t) { TU_TYPE value1 = (TU_TYPE)20.0f; + Unit h1(value1); Unit s1(value1); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> l = pow<(TU_TYPE)2.0>(s1); - t.template assert>(l.base_value, (TU_TYPE)pow(value1, (TU_TYPE)2.0) * (TU_TYPE)1.0e-6f, __LINE__); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> l1 = pow>(s1); + t.template assert>(l1.base_value, (TU_TYPE)pow(value1, (TU_TYPE)2.0) * (TU_TYPE)1.0e-6f, __LINE__); + + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> l2 = pow>(h1); + t.template assert>(l2.base_value, (TU_TYPE)pow(value1, (TU_TYPE)2.0) * (TU_TYPE)1.0e-6f, __LINE__); } ); Test<"sqrt Coherent_unit_base">( [](T &t) { TU_TYPE value = 4.0; - Coherent_unit_base<(TU_TYPE)2.0, (TU_TYPE)4.0, (TU_TYPE)6.0, (TU_TYPE)8.0, (TU_TYPE)10.0, (TU_TYPE)12.0, (TU_TYPE)14.0> r(value); - Coherent_unit_base<(TU_TYPE)1.0, (TU_TYPE)2.0, (TU_TYPE)3.0, (TU_TYPE)4.0, (TU_TYPE)5.0, (TU_TYPE)6.0, (TU_TYPE)7.0> l = sqrt(r); + Coherent_unit_base, std::ratio<4>, std::ratio<6>, std::ratio<8>, std::ratio<10>, std::ratio<12>, std::ratio<14>> r(value); + Coherent_unit_base, std::ratio<2>, std::ratio<3>, std::ratio<4>, std::ratio<5>, std::ratio<6>, std::ratio<7>> l = sqrt(r); t.template assert>(std::sqrt(value), l.base_value, __LINE__); } ); @@ -447,7 +496,7 @@ int main() { [](T &t) { TU_TYPE value1 = 20.0; Unit s1(value1); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> l = sqrt(s1); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> l = sqrt(s1); t.template assert>(l.base_value, std::sqrt(value1) * std::pow((TU_TYPE)1e-3, (TU_TYPE)0.5), __LINE__); } ); @@ -455,12 +504,12 @@ int main() { Test<"unop Coherent_unit_base">( [](T &t) { TU_TYPE val = 0.0; - auto scalar2 = Coherent_unit_base<(TU_TYPE)0.0>((TU_TYPE)tu::PI/2.0); - auto scalar = Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>(); + auto scalar2 = Coherent_unit_base>((TU_TYPE)tu::PI/2.0); + auto scalar = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>(); t.template assert>(unop(scalar).base_value, (TU_TYPE)0.0, __LINE__); t.template assert>(unop(scalar2).base_value, (TU_TYPE)1.0, __LINE__); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> scalar3 = unop(scalar); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> scalar3 = unop(scalar); // lambda is globally defined to compile with gcc auto new_scalar_2 = unop(scalar); @@ -478,7 +527,7 @@ int main() { Unit new_scalar_unit = unop(scalar_unit); - Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>> scalar3 = unop(scalar_unit); + Coherent_unit>, m>, kg>, A>, K>, mol>, cd>> scalar3 = unop(scalar_unit); t.template assert>(unop(scalar_unit).base_value, (TU_TYPE)1.0, __LINE__); t.template assert>(unop(scalar_unit2).base_value, (TU_TYPE)0.0, __LINE__); @@ -504,33 +553,35 @@ int main() { } ); - Test<"powexp">( + Test<"Coherent units definition">( [](T) { - static_assert(powexp<(TU_TYPE)-2.0>::exp == -2); - static_assert(powexp<(TU_TYPE)-1.0>::exp == -1); - static_assert(powexp<(TU_TYPE)0.0>::exp == 0); - static_assert(powexp<(TU_TYPE)1.0>::exp == 1); - static_assert(powexp<(TU_TYPE)2.0>::exp == 2); - static_assert(powexp<(TU_TYPE)-2.0>::exp != 1); - static_assert(powexp<(TU_TYPE)-1.0>::exp != 1); - static_assert(powexp<(TU_TYPE)0.0>::exp != 1); - static_assert(powexp<(TU_TYPE)1.0>::exp != 0); - static_assert(powexp<(TU_TYPE)2.0>::exp != 1); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, second>::value); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, metre>::value); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, kilogram>::value); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, ampere>::value); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, kelvin>::value); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, mole>::value); + static_assert(std::is_base_of>, m>, kg>, A>, K>, mol>, cd>>, candela >::value); } ); - Test<"Coherent units definition">( - [](T) { - static_assert(std::is_base_of, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>, second>::value); - static_assert(std::is_base_of, m<(TU_TYPE)1.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>, metre>::value); - static_assert(std::is_base_of, m<(TU_TYPE)0.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>, kilogram>::value); - static_assert(std::is_base_of, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>, ampere>::value); - static_assert(std::is_base_of, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)1.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>, kelvin>::value); - static_assert(std::is_base_of, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)1.0>, cd<(TU_TYPE)0.0>>, mole>::value); - static_assert(std::is_base_of, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)1.0>>, candela >::value); - } + Test<"scalar binary operations">( + [](T &t) { + + Unit mult_res = Unit((TU_TYPE)2.0) * scalar((TU_TYPE)100.0); + Unit div_res = Unit((TU_TYPE)400.0) / scalar((TU_TYPE)2.0); + + t.assert_true(mult_res.value == (TU_TYPE)200.0, __LINE__); + t.assert_true(div_res.value == (TU_TYPE)200.0, __LINE__); + + Unit add_res = Unit((TU_TYPE)2.0) + scalar((TU_TYPE)1.0); + Unit sub_res = Unit((TU_TYPE)2.0) - scalar((TU_TYPE)1.0); + + t.assert_true(add_res.value == (TU_TYPE)3.0, __LINE__); + t.assert_true(add_res.value == (TU_TYPE)3.0, __LINE__); + } + ); - static_assert(tu::hour::base_multiplier == 3600.0f); return Test_stats::fail; } \ No newline at end of file diff --git a/typesafe_units/include/tu/typesafe_units.h b/typesafe_units/include/tu/typesafe_units.h index a795d6d..9914205 100644 --- a/typesafe_units/include/tu/typesafe_units.h +++ b/typesafe_units/include/tu/typesafe_units.h @@ -12,15 +12,63 @@ #include #include #include +#include +#include namespace tu { -constexpr TU_TYPE PI = (TU_TYPE)3.1415926535897932384626433832795028841971693993751; +constexpr TU_TYPE PI = std::numbers::pi_v; + +namespace internal { + +template +struct is_ratio : std::false_type {}; + +template +struct is_ratio> : std::true_type {}; + +template +inline constexpr bool is_ratio_v = is_ratio::value; + +template +concept Ratio = is_ratio_v; + +//} + +template +constexpr TU_TYPE fraction(R) { + return static_cast(R::num) / static_cast(R::den); +} + +struct Plus { + template + constexpr auto operator() (A, B) -> std::ratio_add::type{ + return {}; + } +}; + +struct Minus { + template + constexpr auto operator() (A, B) -> std::ratio_subtract::type{ + return {}; + } +}; + +struct Multiply { + template + constexpr auto operator() (A, B) -> std::ratio_multiply::type{ + return {}; + } +}; + +} // namespace internal // -// Prefixes used to define units. +// Prefixes used to define Units. // enum struct prefix { + quecto = -30, + ronto = -27, yocto = -24, zepto = -21, atto = -18, @@ -42,9 +90,10 @@ enum struct prefix { exa = 18, zetta = 21, yotta = 24, + ronna = 27, + quetta = 30, }; - namespace internal { // // Returns compile time calculation of 10^exp. @@ -66,19 +115,9 @@ constexpr TU_TYPE pow10() noexcept { } } -// -// Convenience struct to wrap a TU_TYPE representing an exponent in a template argument. -// This makes it possibel to deduce the exponent argument from a function parameter. -// -template -struct powexp { - constexpr powexp() noexcept {}; - static constexpr TU_TYPE exp = e; -}; - -template +template constexpr bool are_args_zero() noexcept { - if constexpr (U_first != (TU_TYPE)0.0) { + if constexpr (U_first::num != 0) { return false; } else if constexpr (sizeof...(U_args) > 0) { @@ -95,17 +134,17 @@ constexpr bool are_args_zero() noexcept { // template arguments to derive from it. Empty base optimization ensures that // this construction does not come with any memory overhead. // -struct Unit_fundament{ +struct Unit_fundament { auto operator <=> (const Unit_fundament& other) const noexcept = default; }; // // Base struct for coherent units. -// The variadic TU_TYPE arguments simplifies binary operations of units. +// The variadic std::ratio arguments simplifies binary operations of units. // Direct use of this struct should be avoided in application code since it is -// not explicit what quantity each template argument represent. +// not explicit what quantity each template argument represents. // -// Template arguments represents power (p) of SI quantities in the following +// Template arguments represents rational power (p) of SI quantities in the following // order: // //

{}; // -// Struct representation of base unit m (metre) with power p +// Struct representation of base unit m (metre) with rational power p // -template +template struct m : internal::Base_unit

{}; // -// Struct representation of base unit kg (kilogram) with power p +// Struct representation of base unit kg (kilogram) with rational power p // -template +template struct kg : internal::Base_unit

{}; // -// Struct representation of base unit A (ampere) with power p +// Struct representation of base unit A (ampere) with rational power p // -template +template struct A : internal::Base_unit

{}; // -// Struct representation of base unit K (kelvin) with power p +// Struct representation of base unit K (kelvin) with rational power p // -template +template struct K : internal::Base_unit

{}; // -// Struct representation of base unit mol (mole) with power p +// Struct representation of base unit mol (mole) with rational power p // -template +template struct mol : internal::Base_unit

{}; // -// Struct representation of base unit cd (candela) with power p +// Struct representation of base unit cd (candela) with rational power p // -template +template struct cd : internal::Base_unit

{}; // @@ -206,25 +259,25 @@ struct cd : internal::Base_unit

{}; // of coherent units. // template -concept Second_power = std::is_same, Ty>::value; +concept Second_power = std::is_same, Ty>::value; template -concept Metre_power = std::is_same, Ty>::value; +concept Metre_power = std::is_same, Ty>::value; template -concept Kilogram_power = std::is_same, Ty>::value; +concept Kilogram_power = std::is_same, Ty>::value; template -concept Ampere_power = std::is_same, Ty>::value; +concept Ampere_power = std::is_same, Ty>::value; template -concept Kelvin_power = std::is_same, Ty>::value; +concept Kelvin_power = std::is_same, Ty>::value; template -concept Mole_power = std::is_same, Ty>::value; +concept Mole_power = std::is_same, Ty>::value; template -concept Candela_power = std::is_same, Ty>::value; +concept Candela_power = std::is_same, Ty>::value; // // Struct that represents a coherent unit. @@ -239,9 +292,10 @@ template -struct Coherent_unit: internal::Coherent_unit_base { +struct Coherent_unit: internal::Coherent_unit_base { Coherent_unit() = default; - Coherent_unit(const internal::Coherent_unit_base& cb) : internal::Coherent_unit_base(cb) {} + Coherent_unit(const internal::Coherent_unit_base& cb) : internal::Coherent_unit_base(cb) {} + Coherent_unit(TU_TYPE v) : internal::Coherent_unit_base(v){} }; namespace internal { @@ -250,7 +304,7 @@ namespace internal { // Quantities of base are assumed to be in the intended order. // Dimenisons are deduced from base. // -template +template constexpr auto create_coherent_unit(const Coherent_unit_base& cb) noexcept { return Coherent_unit, m, kg, A, K, mol, cd>(cb); } @@ -261,7 +315,7 @@ constexpr auto create_coherent_unit(const Coherent_unit_base -requires (std::derived_from && multiplier != (TU_TYPE)0.0) +requires (std::derived_from && (multiplier != (TU_TYPE)1.0 || adder != (TU_TYPE)0.0)) struct Non_coherent_unit : Parent_unit { static constexpr TU_TYPE base_multiplier = Parent_unit::base_multiplier * multiplier; static constexpr TU_TYPE base_adder = Parent_unit::base_adder + adder * multiplier; @@ -272,7 +326,7 @@ struct Non_coherent_unit : Parent_unit { // Express one unit with prefix in a different unit. // Example: // Unit m(1.0f); -// std::cout << tu::convert_to(m).value << std::endl; // prints 60000.0 +// std::cout << tu::convert_to(m).value << std::endl; // prints 60000.0 // template convert_to(const Unit& from) no // Unit is the intended public unit class. // Prefix is an enum class intrinsically converted to the exponent of the prefix. // Example: -// Unit s = 3.0; -// +// Unit s = 3.0; +// template requires std::derived_from struct Unit : U::Base { @@ -305,135 +359,98 @@ struct Unit : U::Base { // // Define binary operations +, -, *, and / for units. // -template typename T> -auto operator + (T l, T r) noexcept { - return internal::create_coherent_unit(T(l.base_value + r.base_value)); +template +auto operator + (internal::Coherent_unit_base l, internal::Coherent_unit_base r) noexcept { + return internal::create_coherent_unit(internal::Coherent_unit_base(l.base_value + r.base_value)); } -template typename T> -auto operator - (T l, T r) noexcept { - return internal::create_coherent_unit(T(l.base_value - r.base_value)); +template +auto operator - (internal::Coherent_unit_base l, internal::Coherent_unit_base r) noexcept { + return internal::create_coherent_unit(internal::Coherent_unit_base(l.base_value - r.base_value)); } namespace internal { -template typename L, - TU_TYPE rf, - TU_TYPE... r_args, - template typename R, - TU_TYPE... lr_args, - template typename L_op_R, +template requires (sizeof...(l_args) == sizeof...(r_args)) -constexpr auto binary_op_args(L, R, L_op_R, Op op) noexcept { +constexpr auto binary_op_args(internal::Coherent_unit_base, internal::Coherent_unit_base, internal::Coherent_unit_base, Op op) noexcept { if constexpr (sizeof...(l_args) == 0 && sizeof...(r_args) == 0) { - return create_coherent_unit(L_op_R()); + return create_coherent_unit(internal::Coherent_unit_base()); } else { - return binary_op_args(L(), R< r_args...>(), L_op_R(), op); + return binary_op_args(internal::Coherent_unit_base(), internal::Coherent_unit_base(), internal::Coherent_unit_base(), op); } } } // namespace internal -template typename L, - template typename R> +template requires (sizeof...(L_args) == sizeof...(R_args)) -auto operator * (L l, R r) noexcept -> decltype(internal::binary_op_args(L(), - R(), - L<>(), - std::plus())) { +auto operator * (internal::Coherent_unit_base l, + internal::Coherent_unit_base r) noexcept -> decltype(internal::binary_op_args(internal::Coherent_unit_base(), + internal::Coherent_unit_base(), + internal::Coherent_unit_base<>(), + internal::Plus())) { return {l.base_value * r.base_value}; } -template typename L, - template typename R> +template requires (sizeof...(L_args) == sizeof...(R_args)) -auto operator / (L l, R r) noexcept -> decltype(internal::binary_op_args(L(), - R(), - L<>(), - std::minus())) { +auto operator / (internal::Coherent_unit_base l, + internal::Coherent_unit_base r) noexcept -> decltype(internal::binary_op_args(internal::Coherent_unit_base(), + internal::Coherent_unit_base(), + internal::Coherent_unit_base<>(), + internal::Minus())) { return {l.base_value / r.base_value}; } namespace internal { // -// Apply a binary operation Op recusively to every template argument of U and a number n. -// Given U and the number n, the returned type of the operation is U +// Apply a binary operation Op recusively to every template argument of U and a ratio r. +// Given U and the ratio r, the returned type of the operation is U // -template typename U, - TU_TYPE... U_op_args, - template typename U_op, - TU_TYPE n, - template typename Num, +template -constexpr auto binary_op_args_num(U, [[maybe_unused]] Num N, U_op, Op op) noexcept { +constexpr auto binary_op_args_num(internal::Coherent_unit_base, [[maybe_unused]] R r, internal::Coherent_unit_base, Op op) noexcept { if constexpr (sizeof...(U_args) == 0) { - return internal::create_coherent_unit(U_op()); + return internal::create_coherent_unit(internal::Coherent_unit_base()); } else { - return binary_op_args_num(U(), N, U_op(), op); + return binary_op_args_num(internal::Coherent_unit_base(), r, internal::Coherent_unit_base(), op); } } - - -// -// Use the `binary_op_args_num` template functions to perform pow(U). -// Binary operation is std::multiplies. -// -template typename U> -requires std::derived_from, Unit_fundament> -auto pow(U u) noexcept -> decltype(binary_op_args_num(U(), - powexp(), - U<>(), - std::multiplies())) { - return {std::pow(u.base_value, exp)}; -} } //namespace internal - -// -// Template function for pow(Unit) returning the underlying "coherent" unit U::Base -// -template -requires std::derived_from -auto pow(Unit u) noexcept { - return pow(static_cast::Base&>(u)); -} - // -// sqrt for struct Unit. +// Use the `binary_op_args_num` template functions to perform pow>(U...>). +// Binary operation is Multiply. // -template -requires std::derived_from -auto sqrt(Unit u) noexcept { - return pow<(TU_TYPE)0.5>(u); +template +auto pow(internal::Coherent_unit_base u) noexcept -> decltype(binary_op_args_num(internal::Coherent_unit_base(), + exp(), + internal::Coherent_unit_base<>(), + internal::Multiply())) { + return {std::pow(u.base_value, internal::fraction(exp()))}; } // -// sqrt for struct Coherent_unit<> or similar. +// sqrt for struct Unit and Coherent_unit<> or similar. // -template typename U> -requires std::derived_from, internal::Unit_fundament> -auto sqrt(U u) noexcept { - return pow<(TU_TYPE)0.5>(u); +template +auto sqrt(internal::Coherent_unit_base u) noexcept { + return pow>(u); } // @@ -441,9 +458,9 @@ auto sqrt(U u) noexcept { // unop is a template function that applies any unary function that takes a TU_TYPE // and returns a TU_TYPE to the underlying value of the unit if it is a scalar unit e.g // radian or steradian. The function returns a scalar Coherent_unit initialized with -// the value of the performed operation. This makes it possible to operate with any unary -// function (subjected to the restrictions above) from the standard library on a Unit or -// Coherent_unit. unop can take both unary functions and lambda expressions as +// the resulting value of the performed operation. This makes it possible to operate with +// any unary function (subjected to the restrictions above) from the standard library on a +// Unit or Coherent_unit. unop can take both unary functions and lambda expressions as // template parameter. // // Example: @@ -452,13 +469,13 @@ auto sqrt(U u) noexcept { using Unary_op_func = TU_TYPE(*)(TU_TYPE); template -requires (std::derived_from && Unit::is_scalar()) +requires (Unit::is_scalar()) auto unop(const Unit& u){ return internal::create_coherent_unit(typename U::Base(op(u.base_value))); } template -requires (std::derived_from && U::is_scalar()) +requires (U::is_scalar()) auto unop(const U& u){ return U(op(u.base_value)); } @@ -466,46 +483,47 @@ auto unop(const U& u){ // // Explicit definitions of coherent units. // -struct second : Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct metre : Coherent_unit, m<(TU_TYPE)1.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct kilogram: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct ampere: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct kelvin: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)1.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct mole: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)1.0>, cd<(TU_TYPE)0.0>>{}; -struct candela: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)1.0>>{}; - -// -// Dervived units with special names -// -struct hertz : Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct becquerel: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct ohm: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)-2.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct siemens: Coherent_unit, m<(TU_TYPE)-2.0>, kg<(TU_TYPE)-1.0>, A<(TU_TYPE)2.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct farad: Coherent_unit, m<(TU_TYPE)-2.0>, kg<(TU_TYPE)-1.0>, A<(TU_TYPE)2.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct lumen: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)1.0>>{}; -struct weber: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)-1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct gray: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct sievert: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct watt: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct newton: Coherent_unit, m<(TU_TYPE)1.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct lux: Coherent_unit, m<(TU_TYPE)-2.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)1.0>>{}; -struct radian: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct joule: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct steradian: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct katal: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)1.0>, cd<(TU_TYPE)0.0>>{}; -struct pascal: Coherent_unit, m<(TU_TYPE)-1.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct coulomb: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct henry: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)-2.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct tesla: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)-1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct volt : Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)-1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; +using second = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using metre = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using kilogram = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using ampere = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using kelvin = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using mole = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using candela = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; + +// +// Derived units with special names +// +using scalar = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using hertz = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using becquerel = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using ohm = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using siemens = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using farad = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using lumen = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using weber = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using gray = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using sievert = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using watt = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using newton = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using lux = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using radian = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using joule = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using steradian = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using katal = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using pascal = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using coulomb = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using henry = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using tesla = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using volt = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; // // Derived coherent units // -struct metre_per_second : Coherent_unit, m<(TU_TYPE)1.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct second_squared : Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct metre_cubed: Coherent_unit, m<(TU_TYPE)3.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; -struct metre_squared: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; +using metre_per_second = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using second_squared = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using metre_cubed = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; +using metre_squared = Coherent_unit>, m>, kg>, A>, K>, mol>, cd>>; // // Define non coherent units @@ -515,91 +533,54 @@ struct metre_squared: Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYP // Time // -struct minute : Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second> { - using Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second>::Base; -}; - -struct hour : Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute> { - using Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute>::Base; -}; - -struct day : Non_coherent_unit<(TU_TYPE)24.0, (TU_TYPE)0.0, hour> { - using Non_coherent_unit<(TU_TYPE)24.0, (TU_TYPE)0.0, hour>::Base; -}; +using minute = Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second>; +using hour = Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute>; +using day = Non_coherent_unit<(TU_TYPE)24.0, (TU_TYPE)0.0, hour>; // // Temperature // -struct degree_Celsius : Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin> { - using Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin>::Base; -}; +using degree_Celsius = Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin>; // // Mass // -struct gram : Non_coherent_unit<(TU_TYPE)0.001, (TU_TYPE)0.0, kilogram> { - using Non_coherent_unit<(TU_TYPE)0.001, (TU_TYPE)0.0, kilogram>::Base; -}; - -struct tonne : Non_coherent_unit<(TU_TYPE)1000.0, (TU_TYPE)0.0, kilogram> { - using Non_coherent_unit<(TU_TYPE)1000.0, (TU_TYPE)0.0, kilogram>::Base; -}; - -struct dalton : Non_coherent_unit<(TU_TYPE)1.66053904020e-27, (TU_TYPE)0.0, kilogram> { - using Non_coherent_unit<(TU_TYPE)1.66053904020e-27, (TU_TYPE)0.0, kilogram>::Base; -}; - -struct unified_atomic_mass_unit : Non_coherent_unit<(TU_TYPE)1.66053904020e-27, (TU_TYPE)0.0, kilogram> { - using Non_coherent_unit<(TU_TYPE)1.66053904020e-27, (TU_TYPE)0.0, kilogram>::Base; -}; +using gram = Non_coherent_unit<(TU_TYPE)0.001, (TU_TYPE)0.0, kilogram>; +using tonne = Non_coherent_unit<(TU_TYPE)1000.0, (TU_TYPE)0.0, kilogram>; +using dalton = Non_coherent_unit<(TU_TYPE)1.66053904020e-27, (TU_TYPE)0.0, kilogram>; +using unified_atomic_mass_unit = Non_coherent_unit<(TU_TYPE)1.66053904020e-27, (TU_TYPE)0.0, kilogram>; // // Energy // -struct electronvolt : Non_coherent_unit<(TU_TYPE)1.602176634e-19, (TU_TYPE)0.0, joule> { - using Non_coherent_unit<(TU_TYPE)1.602176634e-19, (TU_TYPE)0.0, joule>::Base; -}; +using electronvolt = Non_coherent_unit<(TU_TYPE)1.602176634e-19, (TU_TYPE)0.0, joule>; // // Volume // -struct litre : Non_coherent_unit<(TU_TYPE)0.001, (TU_TYPE)0.0, metre_cubed> { - using Non_coherent_unit<(TU_TYPE)0.001, (TU_TYPE)0.0, metre_cubed>::Base; -}; +using litre = Non_coherent_unit<(TU_TYPE)0.001, (TU_TYPE)0.0, metre_cubed>; // // Plane- and phase angel // -struct degree : Non_coherent_unit<(TU_TYPE)(PI/180.0), (TU_TYPE)0.0, radian> { - using Non_coherent_unit<(TU_TYPE)(PI/180.0), (TU_TYPE)0.0, radian>::Base; -}; - -struct arc_minute : Non_coherent_unit<(TU_TYPE)(1/60.0), (TU_TYPE)0.0, degree> { - using Non_coherent_unit<(TU_TYPE)(1/60.0), (TU_TYPE)0.0, degree>::Base; -}; - -struct arc_second : Non_coherent_unit<(TU_TYPE)(1/60.0), (TU_TYPE)0.0, arc_minute> { - using Non_coherent_unit<(TU_TYPE)(1/60.0), (TU_TYPE)0.0, arc_minute>::Base; -}; +using degree = Non_coherent_unit<(TU_TYPE)(PI/180.0), (TU_TYPE)0.0, radian>; +using arc_minute = Non_coherent_unit<(TU_TYPE)(1/60.0), (TU_TYPE)0.0, degree>; +using arc_second = Non_coherent_unit<(TU_TYPE)(1/60.0), (TU_TYPE)0.0, arc_minute>; // // Area // -struct hectare : Non_coherent_unit<(TU_TYPE)(10000.0), (TU_TYPE)0.0, metre_squared> { - using Non_coherent_unit<(TU_TYPE)(10000.0), (TU_TYPE)0.0, metre_squared>::Base; -}; +using hectare = Non_coherent_unit<(TU_TYPE)(10000.0), (TU_TYPE)0.0, metre_squared>; // // Length // -struct astronomical_unit : Non_coherent_unit<(TU_TYPE)149597870700.0, (TU_TYPE)0.0, metre> { - using Non_coherent_unit<(TU_TYPE)149597870700.0, (TU_TYPE)0.0, metre>::Base; -}; +using astronomical_unit = Non_coherent_unit<(TU_TYPE)149597870700.0, (TU_TYPE)0.0, metre>; } // namespace tu \ No newline at end of file