2019-10-04 20:21:05 +02:00
[](./LICENSE.md)
2019-05-08 09:52:46 -06:00
[](https://travis-ci.com/mpusz/units)
2019-10-04 08:29:24 +02:00
[](https://bintray.com/mpusz/conan-mpusz/mp-units%3Ampusz/0.3.1%3Astable/link)
[](https://bintray.com/mpusz/conan-mpusz/mp-units%3Ampusz/_latestVersion)
2019-04-06 23:25:35 +02:00
2019-12-23 13:25:49 +01:00
2019-09-17 06:46:10 -06:00
# `mp-units` - A Units Library for C++
2018-08-22 12:11:19 +02:00
2019-12-17 09:15:31 +01:00
## TL;DR
2020-02-15 21:17:52 +00:00
This library is the subject of this ISO C++ proposal: [P1935R2 ](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1935r2.html ). It is explained in this [CppCon 2019 talk ](https://youtu.be/0YW6yxkdhlU ) (slightly dated see below). We are working towards potentially having it standardised for C++23 and are actively looking for parties interested in field trialling the library.
2019-12-17 09:15:31 +01:00
```cpp
2019-12-17 10:12:17 +01:00
#include <units/physical/si/velocity.h>
2020-01-13 11:15:26 +01:00
#include <units/physical/international/velocity.h>
2019-12-17 10:12:17 +01:00
#include <iostream>
using namespace units ;
2019-12-17 10:51:59 +01:00
constexpr Velocity auto avg_speed ( Length auto d , Time auto t )
2019-12-17 09:15:31 +01:00
{
return d / t ;
}
int main ()
{
using namespace si :: literals ;
2020-02-17 15:56:06 +01:00
Velocity auto v1 = avg_speed ( 220 q_km , 2 q_h );
2020-01-13 11:15:26 +01:00
Velocity auto v2 = avg_speed ( si :: length < international :: mile > ( 140 ), si :: time < si :: hour > ( 2 ));
2019-12-17 10:51:59 +01:00
Velocity auto v3 = quantity_cast < si :: metre_per_second > ( v2 );
Velocity auto v4 = quantity_cast < int > ( v3 );
2019-12-17 09:15:31 +01:00
2020-01-13 11:15:26 +01:00
std :: cout << v1 << '\n' ; // 110 km/h
std :: cout << v2 << '\n' ; // 70 mi/h
std :: cout << v3 << '\n' ; // 31.2928 m/s
std :: cout << v4 << '\n' ; // 31 m/s
2019-12-17 09:15:31 +01:00
}
```
2020-02-19 11:01:17 +01:00
Try it on [Compiler Explorer ](https://godbolt.org/z/_Yx6D7 ).
2019-12-17 09:15:31 +01:00
2018-11-17 12:40:06 +01:00
## Summary
2019-12-17 09:15:31 +01:00
`mp-units` is a compile-time enabled Modern C++ library that provides compile-time dimensional
2019-04-06 23:25:35 +02:00
analysis and unit/quantity manipulation. The basic idea and design heavily bases on
2019-10-04 08:29:24 +02:00
`std::chrono::duration` and extends it to work properly with many dimensions.
2018-11-17 12:40:06 +01:00
2018-11-17 15:24:06 +01:00
Here is a small example of possible operations:
2018-11-17 12:40:06 +01:00
```cpp
2019-04-10 17:20:32 +01:00
// simple numeric operations
2020-02-17 15:56:06 +01:00
static_assert ( 10 q_km / 2 == 5 q_km );
2019-04-10 17:20:32 +01:00
// unit conversions
2020-02-17 15:56:06 +01:00
static_assert ( 1 q_h == 3600 q_s );
static_assert ( 1 q_km + 1 q_m == 1001 q_m );
2019-04-10 17:20:32 +01:00
// dimension conversions
2020-02-17 15:56:06 +01:00
static_assert ( 1 q_km / 1 q_s == 1000 q_mps );
static_assert ( 2 q_kmph * 2 q_h == 4 q_km );
static_assert ( 2 q_km / 2 q_kmph == 1 q_h );
2019-04-10 17:20:32 +01:00
2020-02-17 15:56:06 +01:00
static_assert ( 1000 / 1 q_s == 1 q_kHz );
2019-04-10 17:20:32 +01:00
2020-02-17 15:56:06 +01:00
static_assert ( 10 q_km / 5 q_km == 2 );
2018-11-17 12:40:06 +01:00
```
2019-10-17 11:14:29 +02:00
2019-12-17 09:15:31 +01:00
## Getting Started
2019-10-17 11:14:29 +02:00
2019-12-17 09:15:31 +01:00
The library framework consists of a few concepts: quantities, units, dimensions and their
exponents. From the user's point of view the most important is a `quantity` .
A quantity is a concrete amount of a unit for a specified dimension with a specific representation:
2019-10-17 11:14:29 +02:00
```cpp
2019-12-17 09:15:31 +01:00
units :: quantity < units :: si :: dim_length , units :: si :: kilometre , double > d ( 123 );
2019-10-17 11:14:29 +02:00
```
2019-12-17 09:15:31 +01:00
To simplify quantity creation the library provides helper aliases for quantities of different
dimensions. Thanks to then the above example can be rewritten as follows:
2019-10-17 11:14:29 +02:00
```cpp
2019-12-17 09:15:31 +01:00
units :: si :: length < units :: si :: kilometre , double > d ( 123 );
2019-10-17 11:14:29 +02:00
```
2019-12-17 09:15:31 +01:00
To simplify creations of compile-time known constants the library provides UDLs for each unit.
Thanks to them the same code can be as simple as:
2019-10-17 11:14:29 +02:00
```cpp
2019-12-17 09:15:31 +01:00
using namespace units :: si :: literals ;
2020-02-17 15:56:06 +01:00
auto d = 123 q_km ; // units::length<units::si::kilometre, std::int64_t>
2019-12-17 09:15:31 +01:00
```
For brevity, the next examples will assume:
```cpp
using namespace units ;
```
Let's assume that the user wants to write the following code:
```cpp
int main ()
{
using namespace si :: literals ;
2020-02-17 15:56:06 +01:00
auto v1 = avg_speed ( 220 q_km , 2 q_h );
auto v2 = avg_speed ( 140 q_mi , 2 q_h );
2019-12-17 09:15:31 +01:00
// ...
}
```
`avg_speed` is a simple function calculating an average speed from a distance and duration. It can
be implemented as:
```cpp
constexpr si :: velocity < si :: metre_per_second , int > avg_speed ( si :: length < si :: metre > d , si :: time < si :: second > t )
2019-10-17 11:14:29 +02:00
{
return d / t ;
}
```
2019-12-17 09:15:31 +01:00
However, this function will perform unnecessary intermediate conversions (from kilometers to meters,
from hours to seconds, and from meters per second to kilometers per hour). To eliminate all that
overhead we have to write a template function:
2019-10-17 11:14:29 +02:00
```cpp
2019-12-17 09:15:31 +01:00
template < typename U1 , typename R1 , typename U2 , typename R2 >
constexpr auto avg_speed ( si :: length < U1 , R1 > d , si :: time < U2 , R2 > t )
{
return d / t ;
}
2019-10-17 11:14:29 +02:00
```
2019-12-17 09:15:31 +01:00
This function will work for every SI unit and representation without any unnecessary overhead.
It is also simple enough to ensure that the returned type is actually a velocity. However,
it might not always be the case. For more complicated calculations we would like to ensure
that we are returning a correct type and also inform the user of that fact in the function
template interface. Also we might want to implement a truly generic function that will work
efficiently not only with SI units but also with other systems of units like CGS. The solution
to this are C++20 concepts and generic functions.
2019-10-17 11:14:29 +02:00
```cpp
2019-12-17 09:15:31 +01:00
constexpr Velocity auto avg_speed ( Length auto d , Time auto t )
{
return d / t ;
}
2019-10-17 11:14:29 +02:00
```
2019-12-17 09:15:31 +01:00
The units library also tries really hard to print any quantity in the most user friendly
fashion:
```cpp
int main ()
{
using namespace si :: literals ;
2020-01-13 11:15:26 +01:00
using namespace international :: literals ;
2020-02-17 15:56:06 +01:00
Velocity auto v1 = avg_speed ( 220 q_km , 2 q_h );
Velocity auto v2 = avg_speed ( 140 q_mi , 2 q_h );
2019-12-17 09:15:31 +01:00
std :: cout << v1 << '\n' ; // 110 km/h
std :: cout << quantity_cast < si :: metre_per_second > ( speed ) << '\n' ; // 30.5556 m/s
std :: cout << v2 << '\n' ; // 70 mi/h
}
```
2019-10-17 11:14:29 +02:00
## Library design
2019-12-17 09:15:31 +01:00
A detailed `mp-units` library design rationale and documentation can be found in
[doc/DESIGN.md ](doc/DESIGN.md )
2019-10-17 11:14:29 +02:00
2019-04-06 23:25:35 +02:00
## Repository structure
2019-03-07 21:23:50 +01:00
2019-12-17 09:15:31 +01:00
This repository contains three independent `cmake` -based projects:
1. `./src` - header-only project containing whole `mp-units` library
2. `.` - project used as an entry point for library development (it wraps `./src` project
together with usage examples and tests)
3. `./test_package` - library installation and Conan package verification
2019-10-04 08:29:24 +02:00
2019-12-17 09:15:31 +01:00
NOTE: Please note that this repository depends on a git submodule in the `./cmake/common`
2019-05-08 09:52:46 -06:00
subdirectory.
2018-11-17 12:40:06 +01:00
2019-10-17 11:14:29 +02:00
2019-05-08 09:52:46 -06:00
## Building, testing, and installation
2018-11-17 12:40:06 +01:00
2019-05-08 09:52:46 -06:00
For a detailed information on project compilation, testing and reuse please refer to
2019-04-06 23:25:35 +02:00
[doc/INSTALL.md ](doc/INSTALL.md ).
2018-11-17 12:40:06 +01:00
2019-08-05 18:35:18 +02:00
NOTE: This library as of now compiles correctly only with gcc-9.1 and newer.
2018-11-17 12:40:06 +01:00
2019-05-18 13:01:09 +02:00
## Release notes
2019-12-17 09:15:31 +01:00
- 0.5.0 ???
- Major refactoring and rewrite of the library
- Units are now independent from dimensions
- Dimensions are now depended on units (base or coherent units are provided in a class template)
- Quantity gets a Dimension template parameter again (as unit does not provide information about
its dimension anymore)
- Added official CGS system support
- Added official data information system support
- Repository file tree cleanup
2019-12-28 18:59:53 +01:00
- `ratio` refactored to contain `Exp` template parameter
2020-02-19 11:02:45 +01:00
- linear algebra from `std::experimental::math` support added
- SI fundamental constants added
2020-02-19 11:01:36 +01:00
- `q_` prefix applied to all the UDLs
2019-12-17 09:15:31 +01:00
2019-11-17 07:40:02 +01:00
- 0.4.0 Nov 17, 2019
2019-09-18 21:59:57 -06:00
- Support for derived dimensions in `exp` added
- Added `pow()` and `sqrt()` operations on quantities
2019-09-18 21:55:16 -06:00
- `units` removed from a `std::experimental` namespace
2019-09-26 22:30:57 +02:00
- Downcasting facility refactored so the user does not have to write the boilerplate code anymore
2019-10-15 19:03:45 +02:00
- From now on base dimensions should inherit from `base_dimension` class template
2019-11-08 16:51:45 +00:00
- Added unit symbols definitions to `base_dimension` and derived units
2019-10-17 10:16:44 +02:00
- Added support for `operator<<` on `quantity`
2019-11-08 16:51:45 +00:00
- `fmt` support added
- Derived unit factory helpers refactored
2019-10-18 15:34:46 +02:00
- Refactored the way prefixed units are defined
2019-09-18 10:31:58 -06:00
2019-09-18 09:49:17 -06:00
- 0.3.1 Sep 18, 2019
- cmcstl2 dependency changed to range-v3 0.9.1
2019-09-17 06:52:22 -06:00
- 0.3.0 Sep 16, 2019 (CppCon 2019 design)
2019-10-04 08:29:24 +02:00
- The design as described on CppCon 2019 talk (<https://youtu.be/0YW6yxkdhlU>)
2019-08-05 18:35:18 +02:00
- Applied the feedback from the Cologne evening session
- `upcasting_traits` renamed to `downcasting_traits`
- `Dimension` template parameter removed from quantity
- `units` moved to a `std::experimental` namespace
- Leading underscore prefix removed from UDLs
- Added a few more derived dimensions
- `meter` renamed to `metre`
2019-10-04 08:29:24 +02:00
- Missing `operator*` added
2019-08-06 10:44:25 +02:00
- Predefined dimensions moved to a dedicated directory
2019-08-06 19:56:09 +02:00
- `dimension_` prefix removed from names of derived dimensions
2019-09-17 06:46:10 -06:00
- cmcstl2 library updated to 2019.09.19
- `base_dimension` is a value provided as `const&` to the `exp` type
- integrated with Compiler Explorer
2019-10-04 08:29:24 +02:00
- gsl-lite dependency removed
2019-09-17 06:46:10 -06:00
- Fractional dimension exponents support added
- `QuantityOf` concept introduced
2019-10-04 08:29:24 +02:00
- `quantity_cast<U, Rep>()` support added
2019-08-05 18:35:18 +02:00
2019-09-17 06:52:22 -06:00
- 0.2.0 July 18, 2019 (C++Now 2019 design)
2019-10-04 08:29:24 +02:00
- The design as described on C++Now 2019 talk (<https://youtu.be/wKchCktZPHU>)
2019-09-17 07:08:32 -06:00
- Added C++20 features supported by gcc-9.1 (`std::remove_cvref_t` , down with typename, `std::type_identity` )
2019-10-04 08:29:24 +02:00
- Compile-time performance optimizations (`type_list` , `common_ratio` , `ratio` , `conditional_t` )
2019-07-24 11:34:17 +02:00
2019-05-18 13:01:09 +02:00
- 0.1.0 May 18, 2019
- Initial library release
- Begin semantic versioning
2019-05-18 18:15:07 +02:00
- The last version to work with gcc-8