SlideShare a Scribd company logo
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 1/157
Mateusz Pusz
April 8, 2019
Implementing Physical Units
Library for C++
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 2/157
Famous motivating example
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 3/157
• Robotic space probe launched by NASA on
December 11, 1998
• Project costs: $327.6 million
4Developers 2019 | Implementing Physical Units Library for C++
The Mars Climate Orbiter
3
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 4/157
• Robotic space probe launched by NASA on
December 11, 1998
• Project costs: $327.6 million
• Mars Climate Orbiter began the planned
orbital insertion maneuver on September 23,
1999 at 09:00:46 UTC
4Developers 2019 | Implementing Physical Units Library for C++
The Mars Climate Orbiter
3
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 5/157
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 6/157
• Space probe went out of radio contact when it passed behind Mars at 09:04:52 UTC, 49 seconds earlier
than expected
• Communication was never reestablished
• The spacecra disintegrated due to atmospheric stresses
4Developers 2019 | Implementing Physical Units Library for C++
The Mars Climate Orbiter
5
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 7/157
4Developers 2019 | Implementing Physical Units Library for C++
What went wrong?
6
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 8/157
• The primary cause of this discrepancy was that
– one piece of ground so ware supplied by Lockheed Martin produced results in a United States
customary unit, contrary to its So ware Interface Specification (SIS)
– second system, supplied by NASA, expected those results to be in SI units, in accordance with the
SIS
4Developers 2019 | Implementing Physical Units Library for C++
What went wrong?
6
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 9/157
• The primary cause of this discrepancy was that
– one piece of ground so ware supplied by Lockheed Martin produced results in a United States
customary unit, contrary to its So ware Interface Specification (SIS)
– second system, supplied by NASA, expected those results to be in SI units, in accordance with the
SIS
• Specifically
– so ware that calculated the total impulse produced by thruster firings calculated results in pound-
seconds
– the trajectory calculation so ware then used these results to update the predicted position of the
spacecra and expected it to be in newton-seconds
4Developers 2019 | Implementing Physical Units Library for C++
What went wrong?
6
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 10/157
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 11/157
Why do I care?
ANOTHER EXAMPLE
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 12/157
4Developers 2019 | Implementing Physical Units Library for C++
A long time ago in a galaxy far far away...
9
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 13/157
4Developers 2019 | Implementing Physical Units Library for C++
A long time ago in a galaxy far far away...
9
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 14/157
4Developers 2019 | Implementing Physical Units Library for C++
Tactical Flight Computer
10
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 15/157
4Developers 2019 | Implementing Physical Units Library for C++
Tactical Flight Computer
11
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 16/157
void DistanceBearing(double lat1, double lon1,
double lat2, double lon2,
double *Distance, double *Bearing);
4Developers 2019 | Implementing Physical Units Library for C++
What is the correct order?
12
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 17/157
void DistanceBearing(double lat1, double lon1,
double lat2, double lon2,
double *Distance, double *Bearing);
void FindLatitudeLongitude(double Lat, double Lon,
double Bearing, double Distance,
double *lat_out, double *lon_out);
4Developers 2019 | Implementing Physical Units Library for C++
What is the correct order?
12
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 18/157
void DistanceBearing(double lat1, double lon1,
double lat2, double lon2,
double *Distance, double *Bearing);
void FindLatitudeLongitude(double Lat, double Lon,
double Bearing, double Distance,
double *lat_out, double *lon_out);
4Developers 2019 | Implementing Physical Units Library for C++
What is the correct order?
12
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 19/157
double GlidePolar::MacCreadyAltitude(double emcready,
double Distance,
const double Bearing,
const double WindSpeed,
const double WindBearing,
double *BestCruiseTrack,
double *VMacCready,
const bool isFinalGlide,
double *TimeToGo,
const double AltitudeAboveTarget,
const double cruise_efficiency,
const double TaskAltDiff);
4Developers 2019 | Implementing Physical Units Library for C++
double - an ultimate type to express quantity
13
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 20/157
// Air Density(kg/m3) from relative humidity(%),
// temperature(°C) and absolute pressure(Pa)
double AirDensity(double hr, double temp, double abs_press)
{
return (1/(287.06*(temp+273.15))) *
(abs_press - 230.617 * hr * exp((17.5043*temp)/(241.2+temp)));
}
4Developers 2019 | Implementing Physical Units Library for C++
We shouldn't write the code like that anymore
14
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 21/157
4Developers 2019 | Implementing Physical Units Library for C++
DID YOU EVER HAVE TO WRITE THE CODE THIS WAY?
15
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 22/157
4Developers 2019 | Implementing Physical Units Library for C++
Why do we write our code this way?
16
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 23/157
• No support in the C++ Standard Library
– std::chrono helped a lot for time and duration
– date support comes in C++20
– still not enough for full dimensional analysis
4Developers 2019 | Implementing Physical Units Library for C++
Why do we write our code this way?
16
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 24/157
• No support in the C++ Standard Library
– std::chrono helped a lot for time and duration
– date support comes in C++20
– still not enough for full dimensional analysis
• Lack of good alternatives
– poor user experience (i.e. compilation errors)
– heavy dependencies (i.e. Boost.Units)
– custom 3rd party libraries o en not allowed in production code
4Developers 2019 | Implementing Physical Units Library for C++
Why do we write our code this way?
16
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 25/157
• No support in the C++ Standard Library
– std::chrono helped a lot for time and duration
– date support comes in C++20
– still not enough for full dimensional analysis
• Lack of good alternatives
– poor user experience (i.e. compilation errors)
– heavy dependencies (i.e. Boost.Units)
– custom 3rd party libraries o en not allowed in production code
• Implementing a good library by ourselves is hard
4Developers 2019 | Implementing Physical Units Library for C++
Why do we write our code this way?
16
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 26/157
• No support in the C++ Standard Library
– std::chrono helped a lot for time and duration
– date support comes in C++20
– still not enough for full dimensional analysis
• Lack of good alternatives
– poor user experience (i.e. compilation errors)
– heavy dependencies (i.e. Boost.Units)
– custom 3rd party libraries o en not allowed in production code
• Implementing a good library by ourselves is hard
4Developers 2019 | Implementing Physical Units Library for C++
Why do we write our code this way?
Let's do something about that!
16
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 27/157
4Developers 2019 | Implementing Physical Units Library for C++
CURRENT STATE
R E V I E W O F E X I S T I N G S O L U T I O N S
17
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 28/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 29/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 30/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
const auto mph = avg_speed(/* 140 miles */, /* 2 hours */);
std::cout << /* mph */ << " mphn";
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 31/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
const auto mph = avg_speed(/* 140 miles */, /* 2 hours */);
std::cout << /* mph */ << " mphn";
• Compile time safety to make sure that the result is of a correct dimension
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 32/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
const auto mph = avg_speed(/* 140 miles */, /* 2 hours */);
std::cout << /* mph */ << " mphn";
• Compile time safety to make sure that the result is of a correct dimension
• Support for multiple units and unit prefixes
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 33/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
const auto mph = avg_speed(/* 140 miles */, /* 2 hours */);
std::cout << /* mph */ << " mphn";
• Compile time safety to make sure that the result is of a correct dimension
• Support for multiple units and unit prefixes
• No runtime overhead
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 34/157
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
const auto mph = avg_speed(/* 140 miles */, /* 2 hours */);
std::cout << /* mph */ << " mphn";
• Compile time safety to make sure that the result is of a correct dimension
• Support for multiple units and unit prefixes
• No runtime overhead
• I/O output is out-of-scope for now (waiting for std::format())
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
18
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 35/157
• Boost.Units
– authors: Matthias C. Schabel, Steven Watanabe
– https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html
4Developers 2019 | Implementing Physical Units Library for C++
Existing solutions
19
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 36/157
• Boost.Units
– authors: Matthias C. Schabel, Steven Watanabe
– https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html
• Units
– author: Nic Holthaus
– https://github.com/nholthaus/units
4Developers 2019 | Implementing Physical Units Library for C++
Existing solutions
19
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 37/157
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/time.hpp>
#include <boost/units/systems/si/velocity.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/base_units/metric/hour.hpp>
#include <boost/units/base_units/us/mile.hpp>
#include <boost/units/make_scaled_unit.hpp>
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
20
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 38/157
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/time.hpp>
#include <boost/units/systems/si/velocity.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/base_units/metric/hour.hpp>
#include <boost/units/base_units/us/mile.hpp>
#include <boost/units/make_scaled_unit.hpp>
namespace bu = boost::units;
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
20
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 39/157
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/time.hpp>
#include <boost/units/systems/si/velocity.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/base_units/metric/hour.hpp>
#include <boost/units/base_units/us/mile.hpp>
#include <boost/units/make_scaled_unit.hpp>
namespace bu = boost::units;
using kilometer_base_unit = bu::make_scaled_unit<bu::si::length, bu::scale<10, bu::static_rational<3>>>::type;
using length_kilometer = kilometer_base_unit::unit_type;
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
20
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 40/157
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/time.hpp>
#include <boost/units/systems/si/velocity.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/base_units/metric/hour.hpp>
#include <boost/units/base_units/us/mile.hpp>
#include <boost/units/make_scaled_unit.hpp>
namespace bu = boost::units;
using kilometer_base_unit = bu::make_scaled_unit<bu::si::length, bu::scale<10, bu::static_rational<3>>>::type;
using length_kilometer = kilometer_base_unit::unit_type;
using length_mile = bu::us::mile_base_unit::unit_type;
BOOST_UNITS_STATIC_CONSTANT(miles, length_mile);
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
20
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 41/157
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/time.hpp>
#include <boost/units/systems/si/velocity.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/base_units/metric/hour.hpp>
#include <boost/units/base_units/us/mile.hpp>
#include <boost/units/make_scaled_unit.hpp>
namespace bu = boost::units;
using kilometer_base_unit = bu::make_scaled_unit<bu::si::length, bu::scale<10, bu::static_rational<3>>>::type;
using length_kilometer = kilometer_base_unit::unit_type;
using length_mile = bu::us::mile_base_unit::unit_type;
BOOST_UNITS_STATIC_CONSTANT(miles, length_mile);
using time_hour = bu::metric::hour_base_unit::unit_type;
BOOST_UNITS_STATIC_CONSTANT(hours, time_hour);
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
20
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 42/157
• Too generic
template<typename Length, typename Time>
constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t)
{ return d / t; }
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
21
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 43/157
• Too generic
template<typename Length, typename Time>
constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t)
{ return d / t; }
• Is it really a velocity dimension?
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t)
{ return d / t; }
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
21
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 44/157
• Too generic
template<typename Length, typename Time>
constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t)
{ return d / t; }
• Is it really a velocity dimension?
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t)
{ return d / t; }
• Manually repeats built-in dimensional analysis logic
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr bu::quantity<typename bu::divide_typeof_helper<bu::unit<bu::length_dimension, LengthSystem>,
bu::unit<bu::time_dimension, TimeSystem>>::type>
avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t)
{ return d / t; }
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
21
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 45/157
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t);
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
22
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 46/157
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t);
const auto kmph = avg_speed(220 * bu::si::kilo * bu::si::meters, 2 * hours);
std::cout << kmph.value() << " km/hn";
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
22
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 47/157
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t);
const auto kmph = avg_speed(220 * bu::si::kilo * bu::si::meters, 2 * hours);
std::cout << kmph.value() << " km/hn";
const auto mph = avg_speed(140 * miles, 2 * hours);
std::cout << mph.value() << " mphn";
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Toy example
22
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 48/157
• The widest adoption thanks to Boost
• A wide range of systems and base units
• High flexibility and extensibility
• constexpr usage helps in compile-time
• quantity can use any number-like type for its
representation
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Summary
PROS
23
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 49/157
• The widest adoption thanks to Boost
• A wide range of systems and base units
• High flexibility and extensibility
• constexpr usage helps in compile-time
• quantity can use any number-like type for its
representation
• Pre-C++11 design
• Heavily relies on macros and Boost.MPL
• Domain and C++ experts only
– poor compile-time error messages
– no easy way to use non-SI units
– spread over too many small headers (hard to
compile a simple program)
– designed around custom unit systems
• Not possible to explicitly construct a quantity of
known unit from a plain value (even if no
truncation occurs)
4Developers 2019 | Implementing Physical Units Library for C++
Boost.Units: Summary
PROS CONS
23
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 50/157
#include "units.h"
using namespace units::literals;
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
24
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 51/157
#include "units.h"
using namespace units::literals;
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t)
{
const auto v = d / t;
return v;
}
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
24
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 52/157
#include "units.h"
using namespace units::literals;
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t)
{
static_assert(units::traits::is_length_unit<Length>::value);
static_assert(units::traits::is_time_unit<Time>::value);
const auto v = d / t;
static_assert(units::traits::is_velocity_unit<decltype(v)>::value);
return v;
}
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
24
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 53/157
#include "units.h"
using namespace units::literals;
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t)
{
static_assert(units::traits::is_length_unit<Length>::value);
static_assert(units::traits::is_time_unit<Time>::value);
const auto v = d / t;
static_assert(units::traits::is_velocity_unit<decltype(v)>::value);
return v;
}
• Not possible to define template arguments that will provide proper overload resolution because of
unit nesting
using meter_t = units::unit_t<units::unit<std::ratio<1>, units::category::length_unit>>;
using kilometer_t = units::unit_t<units::unit<std::ratio<1000, 1>, meter_t>, std::ratio<0, 1>, std::ratio<0, 1>>>;
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
24
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 54/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
25
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 55/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
const auto kmph = avg_speed(220_km, 2_hr);
std::cout << kmph.value() << " km/hn";
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
25
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 56/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
const auto kmph = avg_speed(220_km, 2_hr);
std::cout << kmph.value() << " km/hn";
const auto mph = avg_speed(140_mi, 2_hr);
std::cout << mph.value() << " mphn";
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
25
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 57/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
const auto kmph = avg_speed(units::length::kilometer_t(220), units::time::hour_t(2));
std::cout << kmph.value() << " km/hn";
const auto mph = avg_speed(units::length::mile_t(140), units::time::hour_t(2));
std::cout << mph.value() << " mphn";
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
26
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 58/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
const auto kmph = avg_speed(units::length::kilometer_t(220), units::time::hour_t(2));
std::cout << kmph.value() << " km/hn";
const auto mph = avg_speed(units::length::mile_t(140), units::time::hour_t(2));
std::cout << mph.value() << " mphn";
meter is a unit not a quantity!
-- Walter Brown
4Developers 2019 | Implementing Physical Units Library for C++
Units: Toy example
26
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 59/157
• Single header file units.h
• The conversions between units are defined as
ratios at compile time
• UDL support
4Developers 2019 | Implementing Physical Units Library for C++
Units: Summary
PROS
27
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 60/157
• Single header file units.h
• The conversions between units are defined as
ratios at compile time
• UDL support
• Not possible to extend with own base units
• Poor compile-time error messages
• No types that represent dimensions (units only)
• Mixing quantities with units
• Not easily suitable for generic programming
4Developers 2019 | Implementing Physical Units Library for C++
Units: Summary
PROS CONS
27
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 61/157
4Developers 2019 | Implementing Physical Units Library for C++
ISSUES WITH CURRENT SOLUTIONS
28
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 62/157
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{ return d * t; }
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation: Boost.Units
29
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 63/157
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{ return d * t; }
error: could not convert ‘boost::units::operator*(const boost::units::quantity<Unit1, X>&,
const boost::units::quantity<Unit2, Y>&) [with Unit1 = boost::units::unit<boost::units::list<boost::units::dim
<boost::units::length_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type>,
boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit,
boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10,
boost::units::static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit,
boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit,
boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit,
boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit,
boost::units::dimensionless_type> > > > > > > > > > >; Unit2 = boost::units::unit<boost::units::list<boost::units::dim
<boost::units::time_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type>,
boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit,
boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10,
boost::units::static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list
<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list
<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list
<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit,
boost::units::dimensionless_type> > > > > > > > > > >; X = double; Y = double; typename
boost::units::multiply_typeof_helper<boost::units::quantity<Unit1, X>, boost::units::quantity<Unit2, Y> >::type =
...
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation: Boost.Units
GCC-8
29
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 64/157
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{ return d * t; }
...
boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension,
boost::units::static_rational<1> >, boost::units::list<boost::units::dim<boost::units::time_base_dimension,
boost::units::static_rational<1> >, boost::units::dimensionless_type> >, boost::units::homogeneous_system
<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit
<boost::units::cgs::gram_base_unit, boost::units::scale<10, boost::units::static_rational<3> > >,
boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit,
boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit,
boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit,
boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >,
void>, double>](t)’ from ‘quantity<unit<list<[...],list<dim<[...],static_rational<1>>,[...]>>,[...],[...]>,[...]>’
to ‘quantity<unit<list<[...],list<dim<[...],static_rational<-1>>,[...]>>,[...],[...]>,[...]>’
return d * t;
~~^~~
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation: Boost.Units
GCC-8 (CONTINUED)
30
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 65/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t) { return d * t; }
error: static assertion failed: Units are not compatible.
static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible.");
^~~~~~
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation: Units
GCC-8
31
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 66/157
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t) { return d * t; }
error: static assertion failed: Units are not compatible.
static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible.");
^~~~~~
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation: Units
GCC-8
static_assert's are o en not the best solution
• do not influence the overload resolution process
• for some compilers do not provide enough context
31
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 67/157
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging: Boost.Units
32
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 68/157
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging: Boost.Units
32
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 69/157
Breakpoint 1, (anonymous namespace)::avg_speed<boost::units::heterogeneous_system<boost::units::heterogeneous_system_impl
<boost::units::list<boost::units::heterogeneous_system_dim<boost::units::si::meter_base_unit, boost::units::static_rational<1> >,
boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::length_base_dimension,
boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::scale_list_dim
<boost::units::scale<10, boost::units::static_rational<3> > >, boost::units::dimensionless_type> > >,
boost::units::heterogeneous_system<boost::units::heterogeneous_system_impl<boost::units::list
<boost::units::heterogeneous_system_dim<boost::units::scaled_base_unit<boost::units::si::second_base_unit,
boost::units::scale<60, boost::units::static_rational<2> > >, boost::units::static_rational<1> >,
boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::time_base_dimension,
boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::dimensionless_type> > > (d=..., t=...) at
velocity_2.cpp:39
39 return d / t;
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging: Boost.Units
33
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 70/157
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging: Units
34
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 71/157
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging: Units
34
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 72/157
Breakpoint 1, (anonymous namespace)::avg_speed<units::unit_t<units::unit<std::ratio<1000, 1>, units::unit<std::ratio<1>,
units::base_unit<std::ratio<1> > >, std::ratio<0, 1>, std::ratio<0, 1> > >, units::unit_t<units::unit<std::ratio<60>,
units::unit<std::ratio<60>, units::unit<std::ratio<1>, units::base_unit<std::ratio<0, 1>, std::ratio<0, 1>,
std::ratio<1> > > > > > >
(d=..., t=...) at velocity.cpp:28
28 const auto v = d / t;
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging: Units
35
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 73/157
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(foot_base_unit, meter_base_unit, double, 0.3048);
BOOST_UNITS_DEFINE_CONVERSION_OFFSET(celsius_base_unit, fahrenheit_base_unit, double, 32.0);
BOOST_UNITS_DEFAULT_CONVERSION(my_unit_tag, SI::force);
BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE((long N1)(long N2),
currency_base_unit<N1>,
currency_base_unit<N2>,
double, get_conversion_factor(N1, N2));
and more...
4Developers 2019 | Implementing Physical Units Library for C++
Macros omnipresence: Boost.Units
36
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 74/157
#if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LENGTH_UNITS)
UNIT_ADD_WITH_METRIC_PREFIXES(length, meter, meters, m, unit<std::ratio<1>, units::category::length_unit>)
UNIT_ADD(length, foot, feet, ft, unit<std::ratio<381, 1250>, meters>)
UNIT_ADD(length, mil, mils, mil, unit<std::ratio<1000>, feet>)
UNIT_ADD(length, inch, inches, in, unit<std::ratio<1, 12>, feet>)
UNIT_ADD(length, mile, miles, mi, unit<std::ratio<5280>, feet>)
UNIT_ADD(length, nauticalMile, nauticalMiles, nmi, unit<std::ratio<1852>, meters>)
UNIT_ADD(length, astronicalUnit, astronicalUnits, au, unit<std::ratio<149597870700>, meters>)
UNIT_ADD(length, lightyear, lightyears, ly, unit<std::ratio<9460730472580800>, meters>)
UNIT_ADD(length, parsec, parsecs, pc, unit<std::ratio<648000>, astronicalUnits, std::ratio<-1>>)
UNIT_ADD(length, angstrom, angstroms, angstrom, unit<std::ratio<1, 10>, nanometers>)
UNIT_ADD(length, cubit, cubits, cbt, unit<std::ratio<18>, inches>)
UNIT_ADD(length, fathom, fathoms, ftm, unit<std::ratio<6>, feet>)
UNIT_ADD(length, chain, chains, ch, unit<std::ratio<66>, feet>)
UNIT_ADD(length, furlong, furlongs, fur, unit<std::ratio<10>, chains>)
UNIT_ADD(length, hand, hands, hand, unit<std::ratio<4>, inches>)
UNIT_ADD(length, league, leagues, lea, unit<std::ratio<3>, miles>)
UNIT_ADD(length, nauticalLeague, nauticalLeagues, nl, unit<std::ratio<3>, nauticalMiles>)
UNIT_ADD(length, yard, yards, yd, unit<std::ratio<3>, feet>)
UNIT_ADD_CATEGORY_TRAIT(length)
#endif
4Developers 2019 | Implementing Physical Units Library for C++
Macros omnipresence: Units
37
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 75/157
• Adding derived dimensions is pretty easy in all the libraries
• Adding base dimensions is hard or nearly impossible
4Developers 2019 | Implementing Physical Units Library for C++
Extensibility
38
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 76/157
• Adding derived dimensions is pretty easy in all the libraries
• Adding base dimensions is hard or nearly impossible
struct length_base_dimension : base_dimension<length_base_dimension, 1> {};
struct mass_base_dimension : base_dimension<mass_base_dimension, 2> {};
struct time_base_dimension : base_dimension<time_base_dimension, 3> {};
• Order is completely arbitrary as long as each tag has a unique enumerable value
• Non-unique ordinals are flagged as errors at compile-time
• Negative ordinals are reserved for use by the library
• Two independent libraries can easily choose the same ordinal (i.e. 1)
4Developers 2019 | Implementing Physical Units Library for C++
Extensibility
BOOST.UNITS
38
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 77/157
• Adding derived dimensions is pretty easy in all the libraries
• Adding base dimensions is hard or nearly impossible
template<class Meter = detail::meter_ratio<0>,
class Kilogram = std::ratio<0>,
class Second = std::ratio<0>,
class Radian = std::ratio<0>,
class Ampere = std::ratio<0>,
class Kelvin = std::ratio<0>,
class Mole = std::ratio<0>,
class Candela = std::ratio<0>,
class Byte = std::ratio<0>>
struct base_unit;
• Requires refactoring the engine, all existing predefined and users' unit types
4Developers 2019 | Implementing Physical Units Library for C++
Extensibility
UNITS
39
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 78/157
4Developers 2019 | Implementing Physical Units Library for C++
MY UNITS LIBRARY (WIP!!!)
H T T P S : / / G I T H U B . C O M / M P U S Z / U N I T S
40
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 79/157
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
4Developers 2019 | Implementing Physical Units Library for C++
Requirements
41
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 80/157
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
• The best possible user experience
– compiler errors
– debugging
4Developers 2019 | Implementing Physical Units Library for C++
Requirements
41
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 81/157
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
• The best possible user experience
– compiler errors
– debugging
• No macros in the user interface
• No external dependencies
• Easy extensibility
4Developers 2019 | Implementing Physical Units Library for C++
Requirements
41
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 82/157
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
• The best possible user experience
– compiler errors
– debugging
• No macros in the user interface
• No external dependencies
• Easy extensibility
• Possibility to be standardized as a part of the C++ Standard Library
4Developers 2019 | Implementing Physical Units Library for C++
Requirements
41
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 83/157
• BaseDimension is a unique sortable compile-time value
template<int UniqueValue>
using dim_id = std::integral_constant<int, UniqueValue>;
4Developers 2019 | Implementing Physical Units Library for C++
Dimensions
42
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 84/157
• BaseDimension is a unique sortable compile-time value
template<int UniqueValue>
using dim_id = std::integral_constant<int, UniqueValue>;
struct base_dim_length : dim_id<0> {};
struct base_dim_mass : dim_id<1> {};
struct base_dim_time : dim_id<2> {};
4Developers 2019 | Implementing Physical Units Library for C++
Dimensions
EXAMPLE
42
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 85/157
• BaseDimension is a unique sortable compile-time value
template<int UniqueValue>
using dim_id = std::integral_constant<int, UniqueValue>;
struct base_dim_length : dim_id<0> {};
struct base_dim_mass : dim_id<1> {};
struct base_dim_time : dim_id<2> {};
4Developers 2019 | Implementing Physical Units Library for C++
Dimensions
EXAMPLE
The same problem with extensibility as with Boost.Units. If two users will
select the same ID for their types than we have problems
42
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 86/157
• Allow non-union class types to appear in non-type template parameters
• Require that types used as such, and all of their bases and non-static data members recursively, have a
non-user-provided operator<=> returning a type that is implicitly convertible to
std::strong_equality, and contain no references
4Developers 2019 | Implementing Physical Units Library for C++
P0732 Class Types in Non-Type Template Parameters
43
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 87/157
• Allow non-union class types to appear in non-type template parameters
• Require that types used as such, and all of their bases and non-static data members recursively, have a
non-user-provided operator<=> returning a type that is implicitly convertible to
std::strong_equality, and contain no references
template<fixed_string Id>
class enity { /* ... */ };
entity<"hello"> e;
4Developers 2019 | Implementing Physical Units Library for C++
P0732 Class Types in Non-Type Template Parameters
43
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 88/157
• base_dimension can be either directly fixed_string or a type that will include additional information
(i.e. user's namespace name)
using base_dimension = fixed_string;
4Developers 2019 | Implementing Physical Units Library for C++
C++20 Exponent and Base Dimension
44
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 89/157
• base_dimension can be either directly fixed_string or a type that will include additional information
(i.e. user's namespace name)
using base_dimension = fixed_string;
inline constexpr base_dimension base_dim_length("length");
inline constexpr base_dimension base_dim_time("time");
4Developers 2019 | Implementing Physical Units Library for C++
C++20 Exponent and Base Dimension
EXAMPLE
44
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 90/157
• base_dimension can be either directly fixed_string or a type that will include additional information
(i.e. user's namespace name)
using base_dimension = fixed_string;
inline constexpr base_dimension base_dim_length("length");
inline constexpr base_dimension base_dim_time("time");
4Developers 2019 | Implementing Physical Units Library for C++
C++20 Exponent and Base Dimension
EXAMPLE
Much easier to extend the library with new base dimension without identifier
collisions between vendors
44
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 91/157
1 Generic programming
2 Compile-time errors
3 Debugging
4Developers 2019 | Implementing Physical Units Library for C++
Struggling with the user experience
45
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 92/157
• Is it really a velocity dimension?
template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2>
constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d,
bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t)
{ return d / t; }
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t)
{
static_assert(units::traits::is_length_unit<Length>::value);
static_assert(units::traits::is_time_unit<Time>::value);
const auto v = d / t;
static_assert(units::traits::is_velocity_unit<decltype(v)>::value);
return v;
}
• Not possible to define template arguments that will provide proper overload resolution
4Developers 2019 | Implementing Physical Units Library for C++
Do you remember that?
BOOST.UNITS
UNITS
46
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 93/157
#include <boost/units/is_quantity_of_dimension.hpp>
template<typename Quantity, typename Dimension>
concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value;
4Developers 2019 | Implementing Physical Units Library for C++
C++ Concepts to the rescue
BOOST.UNITS
47
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 94/157
#include <boost/units/is_quantity_of_dimension.hpp>
template<typename Quantity, typename Dimension>
concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value;
template<typename Quantity>
concept Length = QuantityOf<Quantity, bu::length_dimension>;
template<typename Quantity>
concept Time = QuantityOf<Quantity, bu::time_dimension>;
template<typename Quantity>
concept Velocity = QuantityOf<Quantity, bu::velocity_dimension>;
4Developers 2019 | Implementing Physical Units Library for C++
C++ Concepts to the rescue
BOOST.UNITS
47
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 95/157
#include <boost/units/is_quantity_of_dimension.hpp>
template<typename Quantity, typename Dimension>
concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value;
template<typename Quantity>
concept Length = QuantityOf<Quantity, bu::length_dimension>;
template<typename Quantity>
concept Time = QuantityOf<Quantity, bu::time_dimension>;
template<typename Quantity>
concept Velocity = QuantityOf<Quantity, bu::velocity_dimension>;
constexpr Velocity auto avg_speed(Length auto d, Time auto t) { return d / t; }
4Developers 2019 | Implementing Physical Units Library for C++
C++ Concepts to the rescue
BOOST.UNITS
47
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 96/157
template<typename T>
concept Length = units::traits::is_length_unit<T>::value;
template<typename T>
concept Time = units::traits::is_time_unit<T>::value;
template<typename T>
concept Velocity = units::traits::is_velocity_unit<T>::value;
4Developers 2019 | Implementing Physical Units Library for C++
C++ Concepts to the rescue
UNITS
48
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 97/157
template<typename T>
concept Length = units::traits::is_length_unit<T>::value;
template<typename T>
concept Time = units::traits::is_time_unit<T>::value;
template<typename T>
concept Velocity = units::traits::is_velocity_unit<T>::value;
constexpr Velocity auto avg_speed(Length auto d, Time auto t) { return d / t; }
4Developers 2019 | Implementing Physical Units Library for C++
C++ Concepts to the rescue
UNITS
48
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 98/157
template<typename T>
concept Length = units::traits::is_length_unit<T>::value;
template<typename T>
concept Time = units::traits::is_time_unit<T>::value;
template<typename T>
concept Velocity = units::traits::is_velocity_unit<T>::value;
constexpr Velocity auto avg_speed(Length auto d, Time auto t) { return d / t; }
4Developers 2019 | Implementing Physical Units Library for C++
C++ Concepts to the rescue
UNITS
Concepts can be used in places where regular template argument deduction
does not work (i.e. return types, class template parameters, etc).
48
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 99/157
• Velocity is one of the simplest derived dimensions one can imagine
using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>;
4Developers 2019 | Implementing Physical Units Library for C++
Type aliases are great (but not for users)
49
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 100/157
• Velocity is one of the simplest derived dimensions one can imagine
using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>;
• Type aliases names are lost quickly during compilation process
4Developers 2019 | Implementing Physical Units Library for C++
Type aliases are great (but not for users)
49
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 101/157
• Velocity is one of the simplest derived dimensions one can imagine
using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>;
• Type aliases names are lost quickly during compilation process
• As a result user gets huge types in error messages
[with D = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >,
units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >,
std::ratio<1000, 3600> >, long long int>]
4Developers 2019 | Implementing Physical Units Library for C++
Type aliases are great (but not for users)
49
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 102/157
• Velocity is one of the simplest derived dimensions one can imagine
using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>;
• Type aliases names are lost quickly during compilation process
• As a result user gets huge types in error messages
[with D = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >,
units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >,
std::ratio<1000, 3600> >, long long int>]
4Developers 2019 | Implementing Physical Units Library for C++
Type aliases are great (but not for users)
It is a pity that we still do not have strong typedef's in the C++ language :-(
49
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 103/157
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
• We get strong types that do not vanish during compilation process
4Developers 2019 | Implementing Physical Units Library for C++
Inheritance to the rescue
50
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 104/157
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
• We get strong types that do not vanish during compilation process
• Easily applicable only to simple classes because of problems with
– constructors
– assignment operators
– comparison operators
– ...
4Developers 2019 | Implementing Physical Units Library for C++
Inheritance to the rescue
50
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 105/157
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
• We get strong types that do not vanish during compilation process
• Easily applicable only to simple classes because of problems with
– constructors
– assignment operators
– comparison operators
– ...
• CRTP could help but it complicates the design
4Developers 2019 | Implementing Physical Units Library for C++
Inheritance to the rescue
50
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 106/157
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
• We get strong types that do not vanish during compilation process
• Easily applicable only to simple classes because of problems with
– constructors
– assignment operators
– comparison operators
– ...
• CRTP could help but it complicates the design
• Anyway velocity should be considered a helper alias for quantity rather than a strong type
template<Unit U = meter_per_second, Number Rep = double>
using velocity = quantity<dimension_velocity, U, Rep>;
4Developers 2019 | Implementing Physical Units Library for C++
Inheritance to the rescue
50
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 107/157
template<Unit U = meter_per_second, Number Rep = double>
using velocity = quantity<dimension_velocity, U, Rep>;
Velocity auto v = 10_m / 2_s;
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting problem
How to form dimension_velocity from division of dimension_length by
dimension_time?
51
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 108/157
template<typename T>
struct type_identity { using type = T; };
template<typename T>
using type_identity_t = typename type_identity<T>::type;
4Developers 2019 | Implementing Physical Units Library for C++
P0887 The identity metafunction
52
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 109/157
template<typename T>
struct upcasting_traits : std::type_identity<T> {};
template<typename T>
using upcasting_traits_t = typename upcasting_traits<T>::type;
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
53
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 110/157
template<typename T>
struct upcasting_traits : std::type_identity<T> {};
template<typename T>
using upcasting_traits_t = typename upcasting_traits<T>::type;
template<typename BaseType>
struct upcast_base {
using base_type = BaseType;
};
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
53
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 111/157
template<typename T>
struct upcasting_traits : std::type_identity<T> {};
template<typename T>
using upcasting_traits_t = typename upcasting_traits<T>::type;
template<typename BaseType>
struct upcast_base {
using base_type = BaseType;
};
template<Exponent... Es>
struct dimension : upcast_base<dimension<Es...>> {};
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
53
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 112/157
template<Exponent... Es>
struct dimension : upcast_base<dimension<Es...>> {};
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
54
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 113/157
template<Exponent... Es>
struct dimension : upcast_base<dimension<Es...>> {};
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
using base = typename dimension_velocity::base_type;
template<>
struct upcasting_traits<base> : std::type_identity<dimension_velocity> {};
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
54
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 114/157
template<Exponent... Es>
struct dimension : upcast_base<dimension<Es...>> {};
struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>,
exp<base_dim_time, -1>> {};
using base = typename dimension_velocity::base_type;
template<>
struct upcasting_traits<base> : std::type_identity<dimension_velocity> {};
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
TBD: Things to consider is to replace upcasting_traits with CRTP
54
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 115/157
[with D = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >,
units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >,
std::ratio<1000, 3600> >, long long int>]
[with D = units::quantity<units::dimension_velocity, units::kilometer_per_hour, long long int>
4Developers 2019 | Implementing Physical Units Library for C++
Upcasting traits
BEFORE
AFTER
55
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 116/157
constexpr units::velocity<units::kilometer_per_hour> avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
56
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 117/157
constexpr units::velocity<units::kilometer_per_hour> avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
error: conversion from ‘quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >,
units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >,
std::ratio<3600000, 1> > ,[...]>’ to non-scalar type ‘quantity<units::dimension_velocity,units::kilometer_per_hour,[...]>’
requested
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
GCC-8
56
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 118/157
constexpr units::velocity<units::kilometer_per_hour> avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
error: conversion from ‘quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >,
units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >,
std::ratio<3600000, 1> > ,[...]>’ to non-scalar type ‘quantity<units::dimension_velocity,units::kilometer_per_hour,[...]>’
requested
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
GCC-8
Repeating of broken dimension type is unfortunate here, but it actually
makes some code (i.e. using CTAD) easier to understand.
Design decision tradeo still to decide...
57
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 119/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
58
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 120/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
velocity.cpp: In instantiation of ‘constexpr units::Velocity {anonymous}::avg_speed(D, T)
[with D = units::quantity<units::dimension_length, units::kilometer, double>;
T = units::quantity<units::dimension_time, units::hour, double>]’:
/mnt/c/repos/units_compare/src/mpusz/velocity.cpp:23:37: required from here
velocity.cpp:12:16:error: placeholder constraints not satisfied
return d * t;
^
include/units/si/velocity.h:47:16: note: within ‘template<class T> concept const bool units::Velocity<T>
[with T = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >,
units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >,
std::ratio<3600000, 1> >, double>]’
concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>;
^~~~~~~~
include/stl2/detail/concepts/core.hpp:37:15: note: within ‘template<class T, class U> concept const bool std::v1::Same<T, U>
[with T = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >;
U = units::dimension_velocity]’
META_CONCEPT Same = meta::Same<T, U> && meta::Same<U, T>;
^~~~
...
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
GCC-8 (FULL ERROR LOG)
58
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 121/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
...
include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U>
[with T = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >;
U = units::dimension_velocity]’
META_CONCEPT Same =
^~~~
include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false
include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U>
[with T = units::dimension_velocity;
U = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >]’
include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
GCC-8 (FULL ERROR LOG - CONTINUED)
59
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 122/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{ return d * t; }
...
include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U>
[with T = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >;
U = units::dimension_velocity]’
META_CONCEPT Same =
^~~~
include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false
include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U>
[with T = units::dimension_velocity;
U = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >]’
include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Compilation
GCC-8 (FULL ERROR LOG - CONTINUED)
Probably it will be improved even more with time...
59
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 123/157
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging
60
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 124/157
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging
60
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 125/157
Breakpoint 1, (anonymous namespace)::avg_speed<units::quantity<units::dimension_length, units::kilometer, double>,
units::quantity<units::dimension_time, units::hour, double> > (d=..., t=...) at velocity.cpp:31
31 return d / t;
4Developers 2019 | Implementing Physical Units Library for C++
User experience: Debugging
61
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 126/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{
return d / t;
}
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
62
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 127/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{
return d / t;
}
const auto kmph = avg_speed(220_km, 2_h);
std::cout << kmph.count() << " km/hn";
const auto mph = avg_speed(140_mi, 2_h);
std::cout << mph.count() << " mphn";
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
62
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 128/157
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{
return d / t;
}
const auto kmph = avg_speed(units::length<units::kilometer>(220), units::time<units::hour>(2));
std::cout << kmph.count() << " km/hn";
const auto mph = avg_speed(units::length<units::mile>(140), units::time<units::hour>(2));
std::cout << mph.count() << " mphn";
4Developers 2019 | Implementing Physical Units Library for C++
Toy example
63
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 129/157
template<class T, class Allocator = std::allocator<T>>
class vector;
4Developers 2019 | Implementing Physical Units Library for C++
C++17 CTAD (Class Template Argument Deduction)
CLASS TEMPLATE
64
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 130/157
template<class T, class Allocator = std::allocator<T>>
class vector;
vector v = {1, 2, 3};
vector v2(cont.begin(), cont.end());
4Developers 2019 | Implementing Physical Units Library for C++
C++17 CTAD (Class Template Argument Deduction)
CLASS TEMPLATE
64
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 131/157
template<class T, class Allocator = std::allocator<T>>
class vector;
vector v = {1, 2, 3};
vector v2(cont.begin(), cont.end());
namespace pmr {
template<class T>
using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>;
}
4Developers 2019 | Implementing Physical Units Library for C++
C++17 CTAD (Class Template Argument Deduction)
CLASS TEMPLATE
ALIAS TEMPLATE
64
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 132/157
template<class T, class Allocator = std::allocator<T>>
class vector;
vector v = {1, 2, 3};
vector v2(cont.begin(), cont.end());
namespace pmr {
template<class T>
using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>;
}
pmr::vector<int> v = {1, 2, 3};
pmr::vector<decltype(cont)::value_type> v2(cont.begin(), cont.end());
4Developers 2019 | Implementing Physical Units Library for C++
C++17 CTAD (Class Template Argument Deduction)
CLASS TEMPLATE
ALIAS TEMPLATE
64
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 133/157
• Adds CTAD support for
– aggregate templates
– type aliases
– inherited constructors
pmr::vector v = {1, 2, 3};
pmr::vector v2(cont.begin(), cont.end());
4Developers 2019 | Implementing Physical Units Library for C++
P1021 Filling holes in Class Template Argument Deduction
ALIAS TEMPLATE
65
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 134/157
template<Dimension D, Unit U, Number Rep> class quantity;
template<Dimension D, Unit U, Number Rep> quantity(Rep r) -> quantity<D, U, Rep>;
template<Unit U = meter, Number Rep = double>
using length = quantity<dimension_length, U, Rep>;
4Developers 2019 | Implementing Physical Units Library for C++
C++20 CTAD in Units
66
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 135/157
template<Dimension D, Unit U, Number Rep> class quantity;
template<Dimension D, Unit U, Number Rep> quantity(Rep r) -> quantity<D, U, Rep>;
template<Unit U = meter, Number Rep = double>
using length = quantity<dimension_length, U, Rep>;
units::length d1(3); // OK -> quantity<dimension_length, meter, int>
units::length d2(3.14); // OK -> quantity<dimension_length, meter, double>
units::length<units::mile> d3(3); // FAIL -> quantity<dimension_length, mile, double>
units::length<units::mile> d4(3.14); // OK -> quantity<dimension_length, mile, double>
units::length<units::mile, float> d5(3.14); // OK -> quantity<dimension_length, mile, float>
4Developers 2019 | Implementing Physical Units Library for C++
C++20 CTAD in Units
66
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 136/157
template<Dimension D, Unit U, Number Rep> class quantity;
template<Dimension D, Unit U, Number Rep> quantity(Rep r) -> quantity<D, U, Rep>;
template<Unit U = meter, Number Rep = double>
using length = quantity<dimension_length, U, Rep>;
units::length d1(3); // OK -> quantity<dimension_length, meter, int>
units::length d2(3.14); // OK -> quantity<dimension_length, meter, double>
units::length<units::mile> d3(3); // FAIL -> quantity<dimension_length, mile, double>
units::length<units::mile> d4(3.14); // OK -> quantity<dimension_length, mile, double>
units::length<units::mile, float> d5(3.14); // OK -> quantity<dimension_length, mile, float>
template<Number Rep = double>
using length_miles = length<mile, Rep>;
units::length_miles d3(3); // OK -> quantity<dimension_length, mile, int>
4Developers 2019 | Implementing Physical Units Library for C++
C++20 CTAD in Units
WORKAROUND THAT I WOULD PREFER NOT TO DO ("METER IS A UNIT NOT A QUANTITY! ")
66
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 137/157
template<Dimension D, Unit U, Number Rep>
requires std::experimental::ranges::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2>
[[nodiscard]] std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != quantity<D, U2, Rep2>(0));
// ...
}
};
4Developers 2019 | Implementing Physical Units Library for C++
Contracts
67
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 138/157
template<Dimension D, Unit U, Number Rep>
requires std::experimental::ranges::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2>
[[nodiscard]] std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != quantity<D, U2, Rep2>(0));
// ...
}
};
error: macro "Expects" passed 3 arguments, but takes just 1
4Developers 2019 | Implementing Physical Units Library for C++
Contracts
67
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 139/157
template<Dimension D, Unit U, Number Rep>
requires std::experimental::ranges::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2>
[[nodiscard]] std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
using rhs_type = quantity<D, U2, Rep2>;
Expects(rhs != rhs_type(0));
// ...
}
};
4Developers 2019 | Implementing Physical Units Library for C++
Contracts
68
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 140/157
template<Dimension D, Unit U, Number Rep>
requires std::experimental::ranges::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2>
[[nodiscard]] std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
// ...
}
};
4Developers 2019 | Implementing Physical Units Library for C++
Contracts
69
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 141/157
template<Dimension D, Unit U, Number Rep>
requires std::experimental::ranges::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2>
[[nodiscard]] std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
// ...
}
};
4Developers 2019 | Implementing Physical Units Library for C++
Contracts
Still not the best solution:
• usage of a macro in a header file (possible ODR issue)
• not a part of a function signature
69
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 142/157
template<Dimension D, Unit U, Number Rep>
requires std::experimental::ranges::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2>
[[nodiscard]] std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs) [[expects: rhs != quantity<D, U2, Rep2>(0)]]
{
// ...
}
};
4Developers 2019 | Implementing Physical Units Library for C++
C++20 Contracts
70
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 143/157
1 What to do with std::chrono::duration?
2 What is the best way to add support for temperatures?
3 Should we provide strong types and upcasting_traits for quantity types?
4 Should we provide aliases for quantities of units (i.e. meters<int>) to workaround CTAD problem?
5 Do we need non-linear scale? How to support it?
4Developers 2019 | Implementing Physical Units Library for C++
Open design questions
71
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 144/157
1 What to do with std::chrono::duration?
2 What is the best way to add support for temperatures?
3 Should we provide strong types and upcasting_traits for quantity types?
4 Should we provide aliases for quantities of units (i.e. meters<int>) to workaround CTAD problem?
5 Do we need non-linear scale? How to support it?
4Developers 2019 | Implementing Physical Units Library for C++
Open design questions
More design questions on the project website
(https://github.com/mpusz/units)
71
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 145/157
We really need physical units and dimensional analysis support in
the C++ Standard Library
4Developers 2019 | Implementing Physical Units Library for C++
Let's join forces!
72
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 146/157
We really need physical units and dimensional analysis support in
the C++ Standard Library
• C++ community and industry really need it
• Great opportunity to learn C++20
• An interesting and hard challenge to solve ;-)
4Developers 2019 | Implementing Physical Units Library for C++
Let's join forces!
WHY TO JOIN?
72
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 147/157
We really need physical units and dimensional analysis support in
the C++ Standard Library
• C++ community and industry really need it
• Great opportunity to learn C++20
• An interesting and hard challenge to solve ;-)
4Developers 2019 | Implementing Physical Units Library for C++
Let's join forces!
WHY TO JOIN?
Please, help...
72
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 148/157
8.04.2019 std::units
file:///C:/repos/cppTrainings/build/out/units/units.html#149 149/157

More Related Content

PDF
A Physical Units Library for the Next C++
PDF
Free Lunch is Over: Why is C++ so Important in the Modern World?
PPTX
carrow - Go bindings to Apache Arrow via C++-API
PDF
Michal Illich: Zuri aneb Vývojáři staví letadlo
PDF
Implementing Physical Units Library for C++. Mateusz Pusz.CoreHard Spring 2019
PDF
Implementing a Physical Units Library for C++
PDF
Effective replacement of dynamic polymorphism with std::variant
PDF
Andrii Soldatenko "The art of data engineering"
A Physical Units Library for the Next C++
Free Lunch is Over: Why is C++ so Important in the Modern World?
carrow - Go bindings to Apache Arrow via C++-API
Michal Illich: Zuri aneb Vývojáři staví letadlo
Implementing Physical Units Library for C++. Mateusz Pusz.CoreHard Spring 2019
Implementing a Physical Units Library for C++
Effective replacement of dynamic polymorphism with std::variant
Andrii Soldatenko "The art of data engineering"

Similar to Implementing Physical Units Library for C++ (20)

PDF
ANSI ISO C Professional Programmer S Handbook
PDF
Rethinking the Way We do Templates in C++
PDF
You got database in my cloud!
PDF
IBM XL Compilers Performance Tuning 2016-11-18
PDF
OpenMP-OpenACC-Offload-Cauldron2022-1.pdf
PPTX
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
PPTX
Introduction-to-C-Part-1.pptx
PDF
Infrastructure-as-Code with Pulumi - Better than all the others (like Ansible)?
DOC
Introduction-to-C-Part-1 (1).doc
PPTX
2013 09-02 senzations-bimschas-part4-setting-up-your-own-testbed
PDF
中国计算机学会推荐国际学术会议和期刊目录-2022.pdf
PDF
silver gemstone sun pendant silver pendant gemstones
PDF
SciPy 2025 - Packaging a Scientific Python Project
PDF
FHIR-first development of healthcare applications
PDF
Solution Manual for C++ How to Program 10th by Deitel
PDF
Cloud-Native Application and Kubernetes
PPT
2 Intro c++
PDF
BuildKitでLazy Pullを有効にしてビルドを早くする話
PPTX
Unit 1 of c++ part 1 basic introduction
ANSI ISO C Professional Programmer S Handbook
Rethinking the Way We do Templates in C++
You got database in my cloud!
IBM XL Compilers Performance Tuning 2016-11-18
OpenMP-OpenACC-Offload-Cauldron2022-1.pdf
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
Introduction-to-C-Part-1.pptx
Infrastructure-as-Code with Pulumi - Better than all the others (like Ansible)?
Introduction-to-C-Part-1 (1).doc
2013 09-02 senzations-bimschas-part4-setting-up-your-own-testbed
中国计算机学会推荐国际学术会议和期刊目录-2022.pdf
silver gemstone sun pendant silver pendant gemstones
SciPy 2025 - Packaging a Scientific Python Project
FHIR-first development of healthcare applications
Solution Manual for C++ How to Program 10th by Deitel
Cloud-Native Application and Kubernetes
2 Intro c++
BuildKitでLazy Pullを有効にしてビルドを早くする話
Unit 1 of c++ part 1 basic introduction
Ad

More from Mateusz Pusz (10)

PDF
Striving for ultimate Low Latency
PDF
C++11 Was Only the Beginning
PDF
C++ Concepts and Ranges - How to use them?
PDF
Effective replacement of dynamic polymorphism with std::variant
PDF
Git, CMake, Conan - How to ship and reuse our C++ projects?
PDF
Beyond C++17
PDF
Pointless Pointers - How to make our interfaces efficient?
PDF
Striving for ultimate Low Latency
PDF
Small Lie in Big O
PDF
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
Striving for ultimate Low Latency
C++11 Was Only the Beginning
C++ Concepts and Ranges - How to use them?
Effective replacement of dynamic polymorphism with std::variant
Git, CMake, Conan - How to ship and reuse our C++ projects?
Beyond C++17
Pointless Pointers - How to make our interfaces efficient?
Striving for ultimate Low Latency
Small Lie in Big O
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
Ad

Recently uploaded (20)

PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
sap open course for s4hana steps from ECC to s4
PPT
Teaching material agriculture food technology
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Cloud computing and distributed systems.
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Big Data Technologies - Introduction.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Encapsulation theory and applications.pdf
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Chapter 3 Spatial Domain Image Processing.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
sap open course for s4hana steps from ECC to s4
Teaching material agriculture food technology
Unlocking AI with Model Context Protocol (MCP)
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Assigned Numbers - 2025 - Bluetooth® Document
Programs and apps: productivity, graphics, security and other tools
Advanced methodologies resolving dimensionality complications for autism neur...
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Diabetes mellitus diagnosis method based random forest with bat algorithm
Cloud computing and distributed systems.
Digital-Transformation-Roadmap-for-Companies.pptx
Reach Out and Touch Someone: Haptics and Empathic Computing
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Big Data Technologies - Introduction.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Encapsulation theory and applications.pdf
Network Security Unit 5.pdf for BCA BBA.
Chapter 3 Spatial Domain Image Processing.pdf

Implementing Physical Units Library for C++

  • 1. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 1/157 Mateusz Pusz April 8, 2019 Implementing Physical Units Library for C++
  • 3. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 3/157 • Robotic space probe launched by NASA on December 11, 1998 • Project costs: $327.6 million 4Developers 2019 | Implementing Physical Units Library for C++ The Mars Climate Orbiter 3
  • 4. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 4/157 • Robotic space probe launched by NASA on December 11, 1998 • Project costs: $327.6 million • Mars Climate Orbiter began the planned orbital insertion maneuver on September 23, 1999 at 09:00:46 UTC 4Developers 2019 | Implementing Physical Units Library for C++ The Mars Climate Orbiter 3
  • 6. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 6/157 • Space probe went out of radio contact when it passed behind Mars at 09:04:52 UTC, 49 seconds earlier than expected • Communication was never reestablished • The spacecra disintegrated due to atmospheric stresses 4Developers 2019 | Implementing Physical Units Library for C++ The Mars Climate Orbiter 5
  • 7. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 7/157 4Developers 2019 | Implementing Physical Units Library for C++ What went wrong? 6
  • 8. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 8/157 • The primary cause of this discrepancy was that – one piece of ground so ware supplied by Lockheed Martin produced results in a United States customary unit, contrary to its So ware Interface Specification (SIS) – second system, supplied by NASA, expected those results to be in SI units, in accordance with the SIS 4Developers 2019 | Implementing Physical Units Library for C++ What went wrong? 6
  • 9. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 9/157 • The primary cause of this discrepancy was that – one piece of ground so ware supplied by Lockheed Martin produced results in a United States customary unit, contrary to its So ware Interface Specification (SIS) – second system, supplied by NASA, expected those results to be in SI units, in accordance with the SIS • Specifically – so ware that calculated the total impulse produced by thruster firings calculated results in pound- seconds – the trajectory calculation so ware then used these results to update the predicted position of the spacecra and expected it to be in newton-seconds 4Developers 2019 | Implementing Physical Units Library for C++ What went wrong? 6
  • 12. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 12/157 4Developers 2019 | Implementing Physical Units Library for C++ A long time ago in a galaxy far far away... 9
  • 13. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 13/157 4Developers 2019 | Implementing Physical Units Library for C++ A long time ago in a galaxy far far away... 9
  • 14. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 14/157 4Developers 2019 | Implementing Physical Units Library for C++ Tactical Flight Computer 10
  • 15. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 15/157 4Developers 2019 | Implementing Physical Units Library for C++ Tactical Flight Computer 11
  • 16. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 16/157 void DistanceBearing(double lat1, double lon1, double lat2, double lon2, double *Distance, double *Bearing); 4Developers 2019 | Implementing Physical Units Library for C++ What is the correct order? 12
  • 17. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 17/157 void DistanceBearing(double lat1, double lon1, double lat2, double lon2, double *Distance, double *Bearing); void FindLatitudeLongitude(double Lat, double Lon, double Bearing, double Distance, double *lat_out, double *lon_out); 4Developers 2019 | Implementing Physical Units Library for C++ What is the correct order? 12
  • 18. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 18/157 void DistanceBearing(double lat1, double lon1, double lat2, double lon2, double *Distance, double *Bearing); void FindLatitudeLongitude(double Lat, double Lon, double Bearing, double Distance, double *lat_out, double *lon_out); 4Developers 2019 | Implementing Physical Units Library for C++ What is the correct order? 12
  • 19. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 19/157 double GlidePolar::MacCreadyAltitude(double emcready, double Distance, const double Bearing, const double WindSpeed, const double WindBearing, double *BestCruiseTrack, double *VMacCready, const bool isFinalGlide, double *TimeToGo, const double AltitudeAboveTarget, const double cruise_efficiency, const double TaskAltDiff); 4Developers 2019 | Implementing Physical Units Library for C++ double - an ultimate type to express quantity 13
  • 20. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 20/157 // Air Density(kg/m3) from relative humidity(%), // temperature(°C) and absolute pressure(Pa) double AirDensity(double hr, double temp, double abs_press) { return (1/(287.06*(temp+273.15))) * (abs_press - 230.617 * hr * exp((17.5043*temp)/(241.2+temp))); } 4Developers 2019 | Implementing Physical Units Library for C++ We shouldn't write the code like that anymore 14
  • 21. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 21/157 4Developers 2019 | Implementing Physical Units Library for C++ DID YOU EVER HAVE TO WRITE THE CODE THIS WAY? 15
  • 22. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 22/157 4Developers 2019 | Implementing Physical Units Library for C++ Why do we write our code this way? 16
  • 23. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 23/157 • No support in the C++ Standard Library – std::chrono helped a lot for time and duration – date support comes in C++20 – still not enough for full dimensional analysis 4Developers 2019 | Implementing Physical Units Library for C++ Why do we write our code this way? 16
  • 24. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 24/157 • No support in the C++ Standard Library – std::chrono helped a lot for time and duration – date support comes in C++20 – still not enough for full dimensional analysis • Lack of good alternatives – poor user experience (i.e. compilation errors) – heavy dependencies (i.e. Boost.Units) – custom 3rd party libraries o en not allowed in production code 4Developers 2019 | Implementing Physical Units Library for C++ Why do we write our code this way? 16
  • 25. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 25/157 • No support in the C++ Standard Library – std::chrono helped a lot for time and duration – date support comes in C++20 – still not enough for full dimensional analysis • Lack of good alternatives – poor user experience (i.e. compilation errors) – heavy dependencies (i.e. Boost.Units) – custom 3rd party libraries o en not allowed in production code • Implementing a good library by ourselves is hard 4Developers 2019 | Implementing Physical Units Library for C++ Why do we write our code this way? 16
  • 26. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 26/157 • No support in the C++ Standard Library – std::chrono helped a lot for time and duration – date support comes in C++20 – still not enough for full dimensional analysis • Lack of good alternatives – poor user experience (i.e. compilation errors) – heavy dependencies (i.e. Boost.Units) – custom 3rd party libraries o en not allowed in production code • Implementing a good library by ourselves is hard 4Developers 2019 | Implementing Physical Units Library for C++ Why do we write our code this way? Let's do something about that! 16
  • 27. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 27/157 4Developers 2019 | Implementing Physical Units Library for C++ CURRENT STATE R E V I E W O F E X I S T I N G S O L U T I O N S 17
  • 28. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 28/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 29. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 29/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 30. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 30/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; const auto mph = avg_speed(/* 140 miles */, /* 2 hours */); std::cout << /* mph */ << " mphn"; 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 31. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 31/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; const auto mph = avg_speed(/* 140 miles */, /* 2 hours */); std::cout << /* mph */ << " mphn"; • Compile time safety to make sure that the result is of a correct dimension 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 32. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 32/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; const auto mph = avg_speed(/* 140 miles */, /* 2 hours */); std::cout << /* mph */ << " mphn"; • Compile time safety to make sure that the result is of a correct dimension • Support for multiple units and unit prefixes 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 33. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 33/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; const auto mph = avg_speed(/* 140 miles */, /* 2 hours */); std::cout << /* mph */ << " mphn"; • Compile time safety to make sure that the result is of a correct dimension • Support for multiple units and unit prefixes • No runtime overhead 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 34. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 34/157 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; const auto mph = avg_speed(/* 140 miles */, /* 2 hours */); std::cout << /* mph */ << " mphn"; • Compile time safety to make sure that the result is of a correct dimension • Support for multiple units and unit prefixes • No runtime overhead • I/O output is out-of-scope for now (waiting for std::format()) 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 18
  • 35. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 35/157 • Boost.Units – authors: Matthias C. Schabel, Steven Watanabe – https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html 4Developers 2019 | Implementing Physical Units Library for C++ Existing solutions 19
  • 36. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 36/157 • Boost.Units – authors: Matthias C. Schabel, Steven Watanabe – https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html • Units – author: Nic Holthaus – https://github.com/nholthaus/units 4Developers 2019 | Implementing Physical Units Library for C++ Existing solutions 19
  • 37. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 37/157 #include <boost/units/quantity.hpp> #include <boost/units/systems/si/length.hpp> #include <boost/units/systems/si/time.hpp> #include <boost/units/systems/si/velocity.hpp> #include <boost/units/systems/si/prefixes.hpp> #include <boost/units/base_units/metric/hour.hpp> #include <boost/units/base_units/us/mile.hpp> #include <boost/units/make_scaled_unit.hpp> 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 20
  • 38. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 38/157 #include <boost/units/quantity.hpp> #include <boost/units/systems/si/length.hpp> #include <boost/units/systems/si/time.hpp> #include <boost/units/systems/si/velocity.hpp> #include <boost/units/systems/si/prefixes.hpp> #include <boost/units/base_units/metric/hour.hpp> #include <boost/units/base_units/us/mile.hpp> #include <boost/units/make_scaled_unit.hpp> namespace bu = boost::units; 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 20
  • 39. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 39/157 #include <boost/units/quantity.hpp> #include <boost/units/systems/si/length.hpp> #include <boost/units/systems/si/time.hpp> #include <boost/units/systems/si/velocity.hpp> #include <boost/units/systems/si/prefixes.hpp> #include <boost/units/base_units/metric/hour.hpp> #include <boost/units/base_units/us/mile.hpp> #include <boost/units/make_scaled_unit.hpp> namespace bu = boost::units; using kilometer_base_unit = bu::make_scaled_unit<bu::si::length, bu::scale<10, bu::static_rational<3>>>::type; using length_kilometer = kilometer_base_unit::unit_type; 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 20
  • 40. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 40/157 #include <boost/units/quantity.hpp> #include <boost/units/systems/si/length.hpp> #include <boost/units/systems/si/time.hpp> #include <boost/units/systems/si/velocity.hpp> #include <boost/units/systems/si/prefixes.hpp> #include <boost/units/base_units/metric/hour.hpp> #include <boost/units/base_units/us/mile.hpp> #include <boost/units/make_scaled_unit.hpp> namespace bu = boost::units; using kilometer_base_unit = bu::make_scaled_unit<bu::si::length, bu::scale<10, bu::static_rational<3>>>::type; using length_kilometer = kilometer_base_unit::unit_type; using length_mile = bu::us::mile_base_unit::unit_type; BOOST_UNITS_STATIC_CONSTANT(miles, length_mile); 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 20
  • 41. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 41/157 #include <boost/units/quantity.hpp> #include <boost/units/systems/si/length.hpp> #include <boost/units/systems/si/time.hpp> #include <boost/units/systems/si/velocity.hpp> #include <boost/units/systems/si/prefixes.hpp> #include <boost/units/base_units/metric/hour.hpp> #include <boost/units/base_units/us/mile.hpp> #include <boost/units/make_scaled_unit.hpp> namespace bu = boost::units; using kilometer_base_unit = bu::make_scaled_unit<bu::si::length, bu::scale<10, bu::static_rational<3>>>::type; using length_kilometer = kilometer_base_unit::unit_type; using length_mile = bu::us::mile_base_unit::unit_type; BOOST_UNITS_STATIC_CONSTANT(miles, length_mile); using time_hour = bu::metric::hour_base_unit::unit_type; BOOST_UNITS_STATIC_CONSTANT(hours, time_hour); 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 20
  • 42. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 42/157 • Too generic template<typename Length, typename Time> constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 21
  • 43. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 43/157 • Too generic template<typename Length, typename Time> constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t) { return d / t; } • Is it really a velocity dimension? template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 21
  • 44. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 44/157 • Too generic template<typename Length, typename Time> constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t) { return d / t; } • Is it really a velocity dimension? template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t) { return d / t; } • Manually repeats built-in dimensional analysis logic template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr bu::quantity<typename bu::divide_typeof_helper<bu::unit<bu::length_dimension, LengthSystem>, bu::unit<bu::time_dimension, TimeSystem>>::type> avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 21
  • 45. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 45/157 template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t); 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 22
  • 46. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 46/157 template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t); const auto kmph = avg_speed(220 * bu::si::kilo * bu::si::meters, 2 * hours); std::cout << kmph.value() << " km/hn"; 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 22
  • 47. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 47/157 template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t); const auto kmph = avg_speed(220 * bu::si::kilo * bu::si::meters, 2 * hours); std::cout << kmph.value() << " km/hn"; const auto mph = avg_speed(140 * miles, 2 * hours); std::cout << mph.value() << " mphn"; 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Toy example 22
  • 48. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 48/157 • The widest adoption thanks to Boost • A wide range of systems and base units • High flexibility and extensibility • constexpr usage helps in compile-time • quantity can use any number-like type for its representation 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Summary PROS 23
  • 49. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 49/157 • The widest adoption thanks to Boost • A wide range of systems and base units • High flexibility and extensibility • constexpr usage helps in compile-time • quantity can use any number-like type for its representation • Pre-C++11 design • Heavily relies on macros and Boost.MPL • Domain and C++ experts only – poor compile-time error messages – no easy way to use non-SI units – spread over too many small headers (hard to compile a simple program) – designed around custom unit systems • Not possible to explicitly construct a quantity of known unit from a plain value (even if no truncation occurs) 4Developers 2019 | Implementing Physical Units Library for C++ Boost.Units: Summary PROS CONS 23
  • 50. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 50/157 #include "units.h" using namespace units::literals; 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 24
  • 51. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 51/157 #include "units.h" using namespace units::literals; template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { const auto v = d / t; return v; } 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 24
  • 52. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 52/157 #include "units.h" using namespace units::literals; template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { static_assert(units::traits::is_length_unit<Length>::value); static_assert(units::traits::is_time_unit<Time>::value); const auto v = d / t; static_assert(units::traits::is_velocity_unit<decltype(v)>::value); return v; } 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 24
  • 53. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 53/157 #include "units.h" using namespace units::literals; template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { static_assert(units::traits::is_length_unit<Length>::value); static_assert(units::traits::is_time_unit<Time>::value); const auto v = d / t; static_assert(units::traits::is_velocity_unit<decltype(v)>::value); return v; } • Not possible to define template arguments that will provide proper overload resolution because of unit nesting using meter_t = units::unit_t<units::unit<std::ratio<1>, units::category::length_unit>>; using kilometer_t = units::unit_t<units::unit<std::ratio<1000, 1>, meter_t>, std::ratio<0, 1>, std::ratio<0, 1>>>; 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 24
  • 54. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 54/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 25
  • 55. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 55/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); const auto kmph = avg_speed(220_km, 2_hr); std::cout << kmph.value() << " km/hn"; 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 25
  • 56. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 56/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); const auto kmph = avg_speed(220_km, 2_hr); std::cout << kmph.value() << " km/hn"; const auto mph = avg_speed(140_mi, 2_hr); std::cout << mph.value() << " mphn"; 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 25
  • 57. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 57/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); const auto kmph = avg_speed(units::length::kilometer_t(220), units::time::hour_t(2)); std::cout << kmph.value() << " km/hn"; const auto mph = avg_speed(units::length::mile_t(140), units::time::hour_t(2)); std::cout << mph.value() << " mphn"; 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 26
  • 58. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 58/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); const auto kmph = avg_speed(units::length::kilometer_t(220), units::time::hour_t(2)); std::cout << kmph.value() << " km/hn"; const auto mph = avg_speed(units::length::mile_t(140), units::time::hour_t(2)); std::cout << mph.value() << " mphn"; meter is a unit not a quantity! -- Walter Brown 4Developers 2019 | Implementing Physical Units Library for C++ Units: Toy example 26
  • 59. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 59/157 • Single header file units.h • The conversions between units are defined as ratios at compile time • UDL support 4Developers 2019 | Implementing Physical Units Library for C++ Units: Summary PROS 27
  • 60. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 60/157 • Single header file units.h • The conversions between units are defined as ratios at compile time • UDL support • Not possible to extend with own base units • Poor compile-time error messages • No types that represent dimensions (units only) • Mixing quantities with units • Not easily suitable for generic programming 4Developers 2019 | Implementing Physical Units Library for C++ Units: Summary PROS CONS 27
  • 61. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 61/157 4Developers 2019 | Implementing Physical Units Library for C++ ISSUES WITH CURRENT SOLUTIONS 28
  • 62. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 62/157 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d * t; } 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation: Boost.Units 29
  • 63. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 63/157 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d * t; } error: could not convert ‘boost::units::operator*(const boost::units::quantity<Unit1, X>&, const boost::units::quantity<Unit2, Y>&) [with Unit1 = boost::units::unit<boost::units::list<boost::units::dim <boost::units::length_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, boost::units::static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > >; Unit2 = boost::units::unit<boost::units::list<boost::units::dim <boost::units::time_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, boost::units::static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list <boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list <boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list <boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > >; X = double; Y = double; typename boost::units::multiply_typeof_helper<boost::units::quantity<Unit1, X>, boost::units::quantity<Unit2, Y> >::type = ... 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation: Boost.Units GCC-8 29
  • 64. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 64/157 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d * t; } ... boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1> >, boost::units::list<boost::units::dim<boost::units::time_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type> >, boost::units::homogeneous_system <boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit <boost::units::cgs::gram_base_unit, boost::units::scale<10, boost::units::static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>](t)’ from ‘quantity<unit<list<[...],list<dim<[...],static_rational<1>>,[...]>>,[...],[...]>,[...]>’ to ‘quantity<unit<list<[...],list<dim<[...],static_rational<-1>>,[...]>>,[...],[...]>,[...]>’ return d * t; ~~^~~ 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation: Boost.Units GCC-8 (CONTINUED) 30
  • 65. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 65/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { return d * t; } error: static assertion failed: Units are not compatible. static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible."); ^~~~~~ 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation: Units GCC-8 31
  • 66. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 66/157 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { return d * t; } error: static assertion failed: Units are not compatible. static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible."); ^~~~~~ 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation: Units GCC-8 static_assert's are o en not the best solution • do not influence the overload resolution process • for some compilers do not provide enough context 31
  • 67. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 67/157 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging: Boost.Units 32
  • 68. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 68/157 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging: Boost.Units 32
  • 69. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 69/157 Breakpoint 1, (anonymous namespace)::avg_speed<boost::units::heterogeneous_system<boost::units::heterogeneous_system_impl <boost::units::list<boost::units::heterogeneous_system_dim<boost::units::si::meter_base_unit, boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::scale_list_dim <boost::units::scale<10, boost::units::static_rational<3> > >, boost::units::dimensionless_type> > >, boost::units::heterogeneous_system<boost::units::heterogeneous_system_impl<boost::units::list <boost::units::heterogeneous_system_dim<boost::units::scaled_base_unit<boost::units::si::second_base_unit, boost::units::scale<60, boost::units::static_rational<2> > >, boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::time_base_dimension, boost::units::static_rational<1> >, boost::units::dimensionless_type>, boost::units::dimensionless_type> > > (d=..., t=...) at velocity_2.cpp:39 39 return d / t; 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging: Boost.Units 33
  • 70. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 70/157 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging: Units 34
  • 71. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 71/157 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging: Units 34
  • 72. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 72/157 Breakpoint 1, (anonymous namespace)::avg_speed<units::unit_t<units::unit<std::ratio<1000, 1>, units::unit<std::ratio<1>, units::base_unit<std::ratio<1> > >, std::ratio<0, 1>, std::ratio<0, 1> > >, units::unit_t<units::unit<std::ratio<60>, units::unit<std::ratio<60>, units::unit<std::ratio<1>, units::base_unit<std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<1> > > > > > > (d=..., t=...) at velocity.cpp:28 28 const auto v = d / t; 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging: Units 35
  • 73. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 73/157 BOOST_UNITS_DEFINE_CONVERSION_FACTOR(foot_base_unit, meter_base_unit, double, 0.3048); BOOST_UNITS_DEFINE_CONVERSION_OFFSET(celsius_base_unit, fahrenheit_base_unit, double, 32.0); BOOST_UNITS_DEFAULT_CONVERSION(my_unit_tag, SI::force); BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE((long N1)(long N2), currency_base_unit<N1>, currency_base_unit<N2>, double, get_conversion_factor(N1, N2)); and more... 4Developers 2019 | Implementing Physical Units Library for C++ Macros omnipresence: Boost.Units 36
  • 74. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 74/157 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LENGTH_UNITS) UNIT_ADD_WITH_METRIC_PREFIXES(length, meter, meters, m, unit<std::ratio<1>, units::category::length_unit>) UNIT_ADD(length, foot, feet, ft, unit<std::ratio<381, 1250>, meters>) UNIT_ADD(length, mil, mils, mil, unit<std::ratio<1000>, feet>) UNIT_ADD(length, inch, inches, in, unit<std::ratio<1, 12>, feet>) UNIT_ADD(length, mile, miles, mi, unit<std::ratio<5280>, feet>) UNIT_ADD(length, nauticalMile, nauticalMiles, nmi, unit<std::ratio<1852>, meters>) UNIT_ADD(length, astronicalUnit, astronicalUnits, au, unit<std::ratio<149597870700>, meters>) UNIT_ADD(length, lightyear, lightyears, ly, unit<std::ratio<9460730472580800>, meters>) UNIT_ADD(length, parsec, parsecs, pc, unit<std::ratio<648000>, astronicalUnits, std::ratio<-1>>) UNIT_ADD(length, angstrom, angstroms, angstrom, unit<std::ratio<1, 10>, nanometers>) UNIT_ADD(length, cubit, cubits, cbt, unit<std::ratio<18>, inches>) UNIT_ADD(length, fathom, fathoms, ftm, unit<std::ratio<6>, feet>) UNIT_ADD(length, chain, chains, ch, unit<std::ratio<66>, feet>) UNIT_ADD(length, furlong, furlongs, fur, unit<std::ratio<10>, chains>) UNIT_ADD(length, hand, hands, hand, unit<std::ratio<4>, inches>) UNIT_ADD(length, league, leagues, lea, unit<std::ratio<3>, miles>) UNIT_ADD(length, nauticalLeague, nauticalLeagues, nl, unit<std::ratio<3>, nauticalMiles>) UNIT_ADD(length, yard, yards, yd, unit<std::ratio<3>, feet>) UNIT_ADD_CATEGORY_TRAIT(length) #endif 4Developers 2019 | Implementing Physical Units Library for C++ Macros omnipresence: Units 37
  • 75. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 75/157 • Adding derived dimensions is pretty easy in all the libraries • Adding base dimensions is hard or nearly impossible 4Developers 2019 | Implementing Physical Units Library for C++ Extensibility 38
  • 76. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 76/157 • Adding derived dimensions is pretty easy in all the libraries • Adding base dimensions is hard or nearly impossible struct length_base_dimension : base_dimension<length_base_dimension, 1> {}; struct mass_base_dimension : base_dimension<mass_base_dimension, 2> {}; struct time_base_dimension : base_dimension<time_base_dimension, 3> {}; • Order is completely arbitrary as long as each tag has a unique enumerable value • Non-unique ordinals are flagged as errors at compile-time • Negative ordinals are reserved for use by the library • Two independent libraries can easily choose the same ordinal (i.e. 1) 4Developers 2019 | Implementing Physical Units Library for C++ Extensibility BOOST.UNITS 38
  • 77. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 77/157 • Adding derived dimensions is pretty easy in all the libraries • Adding base dimensions is hard or nearly impossible template<class Meter = detail::meter_ratio<0>, class Kilogram = std::ratio<0>, class Second = std::ratio<0>, class Radian = std::ratio<0>, class Ampere = std::ratio<0>, class Kelvin = std::ratio<0>, class Mole = std::ratio<0>, class Candela = std::ratio<0>, class Byte = std::ratio<0>> struct base_unit; • Requires refactoring the engine, all existing predefined and users' unit types 4Developers 2019 | Implementing Physical Units Library for C++ Extensibility UNITS 39
  • 78. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 78/157 4Developers 2019 | Implementing Physical Units Library for C++ MY UNITS LIBRARY (WIP!!!) H T T P S : / / G I T H U B . C O M / M P U S Z / U N I T S 40
  • 79. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 79/157 • Safety and performance – strong types – template metaprogramming – constexpr all the things 4Developers 2019 | Implementing Physical Units Library for C++ Requirements 41
  • 80. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 80/157 • Safety and performance – strong types – template metaprogramming – constexpr all the things • The best possible user experience – compiler errors – debugging 4Developers 2019 | Implementing Physical Units Library for C++ Requirements 41
  • 81. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 81/157 • Safety and performance – strong types – template metaprogramming – constexpr all the things • The best possible user experience – compiler errors – debugging • No macros in the user interface • No external dependencies • Easy extensibility 4Developers 2019 | Implementing Physical Units Library for C++ Requirements 41
  • 82. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 82/157 • Safety and performance – strong types – template metaprogramming – constexpr all the things • The best possible user experience – compiler errors – debugging • No macros in the user interface • No external dependencies • Easy extensibility • Possibility to be standardized as a part of the C++ Standard Library 4Developers 2019 | Implementing Physical Units Library for C++ Requirements 41
  • 83. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 83/157 • BaseDimension is a unique sortable compile-time value template<int UniqueValue> using dim_id = std::integral_constant<int, UniqueValue>; 4Developers 2019 | Implementing Physical Units Library for C++ Dimensions 42
  • 84. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 84/157 • BaseDimension is a unique sortable compile-time value template<int UniqueValue> using dim_id = std::integral_constant<int, UniqueValue>; struct base_dim_length : dim_id<0> {}; struct base_dim_mass : dim_id<1> {}; struct base_dim_time : dim_id<2> {}; 4Developers 2019 | Implementing Physical Units Library for C++ Dimensions EXAMPLE 42
  • 85. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 85/157 • BaseDimension is a unique sortable compile-time value template<int UniqueValue> using dim_id = std::integral_constant<int, UniqueValue>; struct base_dim_length : dim_id<0> {}; struct base_dim_mass : dim_id<1> {}; struct base_dim_time : dim_id<2> {}; 4Developers 2019 | Implementing Physical Units Library for C++ Dimensions EXAMPLE The same problem with extensibility as with Boost.Units. If two users will select the same ID for their types than we have problems 42
  • 86. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 86/157 • Allow non-union class types to appear in non-type template parameters • Require that types used as such, and all of their bases and non-static data members recursively, have a non-user-provided operator<=> returning a type that is implicitly convertible to std::strong_equality, and contain no references 4Developers 2019 | Implementing Physical Units Library for C++ P0732 Class Types in Non-Type Template Parameters 43
  • 87. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 87/157 • Allow non-union class types to appear in non-type template parameters • Require that types used as such, and all of their bases and non-static data members recursively, have a non-user-provided operator<=> returning a type that is implicitly convertible to std::strong_equality, and contain no references template<fixed_string Id> class enity { /* ... */ }; entity<"hello"> e; 4Developers 2019 | Implementing Physical Units Library for C++ P0732 Class Types in Non-Type Template Parameters 43
  • 88. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 88/157 • base_dimension can be either directly fixed_string or a type that will include additional information (i.e. user's namespace name) using base_dimension = fixed_string; 4Developers 2019 | Implementing Physical Units Library for C++ C++20 Exponent and Base Dimension 44
  • 89. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 89/157 • base_dimension can be either directly fixed_string or a type that will include additional information (i.e. user's namespace name) using base_dimension = fixed_string; inline constexpr base_dimension base_dim_length("length"); inline constexpr base_dimension base_dim_time("time"); 4Developers 2019 | Implementing Physical Units Library for C++ C++20 Exponent and Base Dimension EXAMPLE 44
  • 90. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 90/157 • base_dimension can be either directly fixed_string or a type that will include additional information (i.e. user's namespace name) using base_dimension = fixed_string; inline constexpr base_dimension base_dim_length("length"); inline constexpr base_dimension base_dim_time("time"); 4Developers 2019 | Implementing Physical Units Library for C++ C++20 Exponent and Base Dimension EXAMPLE Much easier to extend the library with new base dimension without identifier collisions between vendors 44
  • 91. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 91/157 1 Generic programming 2 Compile-time errors 3 Debugging 4Developers 2019 | Implementing Physical Units Library for C++ Struggling with the user experience 45
  • 92. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 92/157 • Is it really a velocity dimension? template<typename LengthSystem, typename Rep1, typename TimeSystem, typename Rep2> constexpr auto avg_speed(bu::quantity<bu::unit<bu::length_dimension, LengthSystem>, Rep1> d, bu::quantity<bu::unit<bu::time_dimension, TimeSystem>, Rep2> t) { return d / t; } template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { static_assert(units::traits::is_length_unit<Length>::value); static_assert(units::traits::is_time_unit<Time>::value); const auto v = d / t; static_assert(units::traits::is_velocity_unit<decltype(v)>::value); return v; } • Not possible to define template arguments that will provide proper overload resolution 4Developers 2019 | Implementing Physical Units Library for C++ Do you remember that? BOOST.UNITS UNITS 46
  • 93. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 93/157 #include <boost/units/is_quantity_of_dimension.hpp> template<typename Quantity, typename Dimension> concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value; 4Developers 2019 | Implementing Physical Units Library for C++ C++ Concepts to the rescue BOOST.UNITS 47
  • 94. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 94/157 #include <boost/units/is_quantity_of_dimension.hpp> template<typename Quantity, typename Dimension> concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value; template<typename Quantity> concept Length = QuantityOf<Quantity, bu::length_dimension>; template<typename Quantity> concept Time = QuantityOf<Quantity, bu::time_dimension>; template<typename Quantity> concept Velocity = QuantityOf<Quantity, bu::velocity_dimension>; 4Developers 2019 | Implementing Physical Units Library for C++ C++ Concepts to the rescue BOOST.UNITS 47
  • 95. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 95/157 #include <boost/units/is_quantity_of_dimension.hpp> template<typename Quantity, typename Dimension> concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value; template<typename Quantity> concept Length = QuantityOf<Quantity, bu::length_dimension>; template<typename Quantity> concept Time = QuantityOf<Quantity, bu::time_dimension>; template<typename Quantity> concept Velocity = QuantityOf<Quantity, bu::velocity_dimension>; constexpr Velocity auto avg_speed(Length auto d, Time auto t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ C++ Concepts to the rescue BOOST.UNITS 47
  • 96. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 96/157 template<typename T> concept Length = units::traits::is_length_unit<T>::value; template<typename T> concept Time = units::traits::is_time_unit<T>::value; template<typename T> concept Velocity = units::traits::is_velocity_unit<T>::value; 4Developers 2019 | Implementing Physical Units Library for C++ C++ Concepts to the rescue UNITS 48
  • 97. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 97/157 template<typename T> concept Length = units::traits::is_length_unit<T>::value; template<typename T> concept Time = units::traits::is_time_unit<T>::value; template<typename T> concept Velocity = units::traits::is_velocity_unit<T>::value; constexpr Velocity auto avg_speed(Length auto d, Time auto t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ C++ Concepts to the rescue UNITS 48
  • 98. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 98/157 template<typename T> concept Length = units::traits::is_length_unit<T>::value; template<typename T> concept Time = units::traits::is_time_unit<T>::value; template<typename T> concept Velocity = units::traits::is_velocity_unit<T>::value; constexpr Velocity auto avg_speed(Length auto d, Time auto t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ C++ Concepts to the rescue UNITS Concepts can be used in places where regular template argument deduction does not work (i.e. return types, class template parameters, etc). 48
  • 99. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 99/157 • Velocity is one of the simplest derived dimensions one can imagine using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>; 4Developers 2019 | Implementing Physical Units Library for C++ Type aliases are great (but not for users) 49
  • 100. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 100/157 • Velocity is one of the simplest derived dimensions one can imagine using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>; • Type aliases names are lost quickly during compilation process 4Developers 2019 | Implementing Physical Units Library for C++ Type aliases are great (but not for users) 49
  • 101. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 101/157 • Velocity is one of the simplest derived dimensions one can imagine using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>; • Type aliases names are lost quickly during compilation process • As a result user gets huge types in error messages [with D = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >, units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >, std::ratio<1000, 3600> >, long long int>] 4Developers 2019 | Implementing Physical Units Library for C++ Type aliases are great (but not for users) 49
  • 102. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 102/157 • Velocity is one of the simplest derived dimensions one can imagine using velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>; • Type aliases names are lost quickly during compilation process • As a result user gets huge types in error messages [with D = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >, units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >, std::ratio<1000, 3600> >, long long int>] 4Developers 2019 | Implementing Physical Units Library for C++ Type aliases are great (but not for users) It is a pity that we still do not have strong typedef's in the C++ language :-( 49
  • 103. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 103/157 struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; • We get strong types that do not vanish during compilation process 4Developers 2019 | Implementing Physical Units Library for C++ Inheritance to the rescue 50
  • 104. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 104/157 struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; • We get strong types that do not vanish during compilation process • Easily applicable only to simple classes because of problems with – constructors – assignment operators – comparison operators – ... 4Developers 2019 | Implementing Physical Units Library for C++ Inheritance to the rescue 50
  • 105. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 105/157 struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; • We get strong types that do not vanish during compilation process • Easily applicable only to simple classes because of problems with – constructors – assignment operators – comparison operators – ... • CRTP could help but it complicates the design 4Developers 2019 | Implementing Physical Units Library for C++ Inheritance to the rescue 50
  • 106. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 106/157 struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; • We get strong types that do not vanish during compilation process • Easily applicable only to simple classes because of problems with – constructors – assignment operators – comparison operators – ... • CRTP could help but it complicates the design • Anyway velocity should be considered a helper alias for quantity rather than a strong type template<Unit U = meter_per_second, Number Rep = double> using velocity = quantity<dimension_velocity, U, Rep>; 4Developers 2019 | Implementing Physical Units Library for C++ Inheritance to the rescue 50
  • 107. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 107/157 template<Unit U = meter_per_second, Number Rep = double> using velocity = quantity<dimension_velocity, U, Rep>; Velocity auto v = 10_m / 2_s; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting problem How to form dimension_velocity from division of dimension_length by dimension_time? 51
  • 108. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 108/157 template<typename T> struct type_identity { using type = T; }; template<typename T> using type_identity_t = typename type_identity<T>::type; 4Developers 2019 | Implementing Physical Units Library for C++ P0887 The identity metafunction 52
  • 109. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 109/157 template<typename T> struct upcasting_traits : std::type_identity<T> {}; template<typename T> using upcasting_traits_t = typename upcasting_traits<T>::type; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits 53
  • 110. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 110/157 template<typename T> struct upcasting_traits : std::type_identity<T> {}; template<typename T> using upcasting_traits_t = typename upcasting_traits<T>::type; template<typename BaseType> struct upcast_base { using base_type = BaseType; }; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits 53
  • 111. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 111/157 template<typename T> struct upcasting_traits : std::type_identity<T> {}; template<typename T> using upcasting_traits_t = typename upcasting_traits<T>::type; template<typename BaseType> struct upcast_base { using base_type = BaseType; }; template<Exponent... Es> struct dimension : upcast_base<dimension<Es...>> {}; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits 53
  • 112. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 112/157 template<Exponent... Es> struct dimension : upcast_base<dimension<Es...>> {}; struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits 54
  • 113. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 113/157 template<Exponent... Es> struct dimension : upcast_base<dimension<Es...>> {}; struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; using base = typename dimension_velocity::base_type; template<> struct upcasting_traits<base> : std::type_identity<dimension_velocity> {}; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits 54
  • 114. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 114/157 template<Exponent... Es> struct dimension : upcast_base<dimension<Es...>> {}; struct dimension_velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {}; using base = typename dimension_velocity::base_type; template<> struct upcasting_traits<base> : std::type_identity<dimension_velocity> {}; 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits TBD: Things to consider is to replace upcasting_traits with CRTP 54
  • 115. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 115/157 [with D = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >, units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, -1> >, std::ratio<1000, 3600> >, long long int>] [with D = units::quantity<units::dimension_velocity, units::kilometer_per_hour, long long int> 4Developers 2019 | Implementing Physical Units Library for C++ Upcasting traits BEFORE AFTER 55
  • 116. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 116/157 constexpr units::velocity<units::kilometer_per_hour> avg_speed(units::Length auto d, units::Time auto t) { return d * t; } 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation 56
  • 117. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 117/157 constexpr units::velocity<units::kilometer_per_hour> avg_speed(units::Length auto d, units::Time auto t) { return d * t; } error: conversion from ‘quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >, units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >, std::ratio<3600000, 1> > ,[...]>’ to non-scalar type ‘quantity<units::dimension_velocity,units::kilometer_per_hour,[...]>’ requested 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation GCC-8 56
  • 118. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 118/157 constexpr units::velocity<units::kilometer_per_hour> avg_speed(units::Length auto d, units::Time auto t) { return d * t; } error: conversion from ‘quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >, units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >, std::ratio<3600000, 1> > ,[...]>’ to non-scalar type ‘quantity<units::dimension_velocity,units::kilometer_per_hour,[...]>’ requested 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation GCC-8 Repeating of broken dimension type is unfortunate here, but it actually makes some code (i.e. using CTAD) easier to understand. Design decision tradeo still to decide... 57
  • 119. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 119/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d * t; } 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation 58
  • 120. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 120/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d * t; } velocity.cpp: In instantiation of ‘constexpr units::Velocity {anonymous}::avg_speed(D, T) [with D = units::quantity<units::dimension_length, units::kilometer, double>; T = units::quantity<units::dimension_time, units::hour, double>]’: /mnt/c/repos/units_compare/src/mpusz/velocity.cpp:23:37: required from here velocity.cpp:12:16:error: placeholder constraints not satisfied return d * t; ^ include/units/si/velocity.h:47:16: note: within ‘template<class T> concept const bool units::Velocity<T> [with T = units::quantity<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >, units::unit<units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >, std::ratio<3600000, 1> >, double>]’ concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>; ^~~~~~~~ include/stl2/detail/concepts/core.hpp:37:15: note: within ‘template<class T, class U> concept const bool std::v1::Same<T, U> [with T = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >; U = units::dimension_velocity]’ META_CONCEPT Same = meta::Same<T, U> && meta::Same<U, T>; ^~~~ ... 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation GCC-8 (FULL ERROR LOG) 58
  • 121. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 121/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d * t; } ... include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U> [with T = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >; U = units::dimension_velocity]’ META_CONCEPT Same = ^~~~ include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U> [with T = units::dimension_velocity; U = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >]’ include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation GCC-8 (FULL ERROR LOG - CONTINUED) 59
  • 122. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 122/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d * t; } ... include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U> [with T = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >; U = units::dimension_velocity]’ META_CONCEPT Same = ^~~~ include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false include/meta/meta_fwd.hpp:206:18: note: within ‘template<class T, class U> concept const bool meta::Same<T, U> [with T = units::dimension_velocity; U = units::dimension<units::exp<units::base_dim_length, 1>, units::exp<units::base_dim_time, 1> >]’ include/meta/meta_fwd.hpp:206:18: note: ‘meta::detail::bool_’ evaluated to false 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Compilation GCC-8 (FULL ERROR LOG - CONTINUED) Probably it will be improved even more with time... 59
  • 123. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 123/157 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging 60
  • 124. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 124/157 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging 60
  • 125. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 125/157 Breakpoint 1, (anonymous namespace)::avg_speed<units::quantity<units::dimension_length, units::kilometer, double>, units::quantity<units::dimension_time, units::hour, double> > (d=..., t=...) at velocity.cpp:31 31 return d / t; 4Developers 2019 | Implementing Physical Units Library for C++ User experience: Debugging 61
  • 126. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 126/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d / t; } 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 62
  • 127. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 127/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d / t; } const auto kmph = avg_speed(220_km, 2_h); std::cout << kmph.count() << " km/hn"; const auto mph = avg_speed(140_mi, 2_h); std::cout << mph.count() << " mphn"; 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 62
  • 128. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 128/157 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d / t; } const auto kmph = avg_speed(units::length<units::kilometer>(220), units::time<units::hour>(2)); std::cout << kmph.count() << " km/hn"; const auto mph = avg_speed(units::length<units::mile>(140), units::time<units::hour>(2)); std::cout << mph.count() << " mphn"; 4Developers 2019 | Implementing Physical Units Library for C++ Toy example 63
  • 129. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 129/157 template<class T, class Allocator = std::allocator<T>> class vector; 4Developers 2019 | Implementing Physical Units Library for C++ C++17 CTAD (Class Template Argument Deduction) CLASS TEMPLATE 64
  • 130. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 130/157 template<class T, class Allocator = std::allocator<T>> class vector; vector v = {1, 2, 3}; vector v2(cont.begin(), cont.end()); 4Developers 2019 | Implementing Physical Units Library for C++ C++17 CTAD (Class Template Argument Deduction) CLASS TEMPLATE 64
  • 131. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 131/157 template<class T, class Allocator = std::allocator<T>> class vector; vector v = {1, 2, 3}; vector v2(cont.begin(), cont.end()); namespace pmr { template<class T> using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>; } 4Developers 2019 | Implementing Physical Units Library for C++ C++17 CTAD (Class Template Argument Deduction) CLASS TEMPLATE ALIAS TEMPLATE 64
  • 132. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 132/157 template<class T, class Allocator = std::allocator<T>> class vector; vector v = {1, 2, 3}; vector v2(cont.begin(), cont.end()); namespace pmr { template<class T> using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>; } pmr::vector<int> v = {1, 2, 3}; pmr::vector<decltype(cont)::value_type> v2(cont.begin(), cont.end()); 4Developers 2019 | Implementing Physical Units Library for C++ C++17 CTAD (Class Template Argument Deduction) CLASS TEMPLATE ALIAS TEMPLATE 64
  • 133. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 133/157 • Adds CTAD support for – aggregate templates – type aliases – inherited constructors pmr::vector v = {1, 2, 3}; pmr::vector v2(cont.begin(), cont.end()); 4Developers 2019 | Implementing Physical Units Library for C++ P1021 Filling holes in Class Template Argument Deduction ALIAS TEMPLATE 65
  • 134. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 134/157 template<Dimension D, Unit U, Number Rep> class quantity; template<Dimension D, Unit U, Number Rep> quantity(Rep r) -> quantity<D, U, Rep>; template<Unit U = meter, Number Rep = double> using length = quantity<dimension_length, U, Rep>; 4Developers 2019 | Implementing Physical Units Library for C++ C++20 CTAD in Units 66
  • 135. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 135/157 template<Dimension D, Unit U, Number Rep> class quantity; template<Dimension D, Unit U, Number Rep> quantity(Rep r) -> quantity<D, U, Rep>; template<Unit U = meter, Number Rep = double> using length = quantity<dimension_length, U, Rep>; units::length d1(3); // OK -> quantity<dimension_length, meter, int> units::length d2(3.14); // OK -> quantity<dimension_length, meter, double> units::length<units::mile> d3(3); // FAIL -> quantity<dimension_length, mile, double> units::length<units::mile> d4(3.14); // OK -> quantity<dimension_length, mile, double> units::length<units::mile, float> d5(3.14); // OK -> quantity<dimension_length, mile, float> 4Developers 2019 | Implementing Physical Units Library for C++ C++20 CTAD in Units 66
  • 136. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 136/157 template<Dimension D, Unit U, Number Rep> class quantity; template<Dimension D, Unit U, Number Rep> quantity(Rep r) -> quantity<D, U, Rep>; template<Unit U = meter, Number Rep = double> using length = quantity<dimension_length, U, Rep>; units::length d1(3); // OK -> quantity<dimension_length, meter, int> units::length d2(3.14); // OK -> quantity<dimension_length, meter, double> units::length<units::mile> d3(3); // FAIL -> quantity<dimension_length, mile, double> units::length<units::mile> d4(3.14); // OK -> quantity<dimension_length, mile, double> units::length<units::mile, float> d5(3.14); // OK -> quantity<dimension_length, mile, float> template<Number Rep = double> using length_miles = length<mile, Rep>; units::length_miles d3(3); // OK -> quantity<dimension_length, mile, int> 4Developers 2019 | Implementing Physical Units Library for C++ C++20 CTAD in Units WORKAROUND THAT I WOULD PREFER NOT TO DO ("METER IS A UNIT NOT A QUANTITY! ") 66
  • 137. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 137/157 template<Dimension D, Unit U, Number Rep> requires std::experimental::ranges::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2> [[nodiscard]] std::common_type_t<Rep1, Rep2> constexpr operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != quantity<D, U2, Rep2>(0)); // ... } }; 4Developers 2019 | Implementing Physical Units Library for C++ Contracts 67
  • 138. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 138/157 template<Dimension D, Unit U, Number Rep> requires std::experimental::ranges::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2> [[nodiscard]] std::common_type_t<Rep1, Rep2> constexpr operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != quantity<D, U2, Rep2>(0)); // ... } }; error: macro "Expects" passed 3 arguments, but takes just 1 4Developers 2019 | Implementing Physical Units Library for C++ Contracts 67
  • 139. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 139/157 template<Dimension D, Unit U, Number Rep> requires std::experimental::ranges::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2> [[nodiscard]] std::common_type_t<Rep1, Rep2> constexpr operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { using rhs_type = quantity<D, U2, Rep2>; Expects(rhs != rhs_type(0)); // ... } }; 4Developers 2019 | Implementing Physical Units Library for C++ Contracts 68
  • 140. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 140/157 template<Dimension D, Unit U, Number Rep> requires std::experimental::ranges::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2> [[nodiscard]] std::common_type_t<Rep1, Rep2> constexpr operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0)); // ... } }; 4Developers 2019 | Implementing Physical Units Library for C++ Contracts 69
  • 141. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 141/157 template<Dimension D, Unit U, Number Rep> requires std::experimental::ranges::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2> [[nodiscard]] std::common_type_t<Rep1, Rep2> constexpr operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0)); // ... } }; 4Developers 2019 | Implementing Physical Units Library for C++ Contracts Still not the best solution: • usage of a macro in a header file (possible ODR issue) • not a part of a function signature 69
  • 142. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 142/157 template<Dimension D, Unit U, Number Rep> requires std::experimental::ranges::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Number Rep1, Unit U2, Number Rep2> [[nodiscard]] std::common_type_t<Rep1, Rep2> constexpr operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[expects: rhs != quantity<D, U2, Rep2>(0)]] { // ... } }; 4Developers 2019 | Implementing Physical Units Library for C++ C++20 Contracts 70
  • 143. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 143/157 1 What to do with std::chrono::duration? 2 What is the best way to add support for temperatures? 3 Should we provide strong types and upcasting_traits for quantity types? 4 Should we provide aliases for quantities of units (i.e. meters<int>) to workaround CTAD problem? 5 Do we need non-linear scale? How to support it? 4Developers 2019 | Implementing Physical Units Library for C++ Open design questions 71
  • 144. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 144/157 1 What to do with std::chrono::duration? 2 What is the best way to add support for temperatures? 3 Should we provide strong types and upcasting_traits for quantity types? 4 Should we provide aliases for quantities of units (i.e. meters<int>) to workaround CTAD problem? 5 Do we need non-linear scale? How to support it? 4Developers 2019 | Implementing Physical Units Library for C++ Open design questions More design questions on the project website (https://github.com/mpusz/units) 71
  • 145. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 145/157 We really need physical units and dimensional analysis support in the C++ Standard Library 4Developers 2019 | Implementing Physical Units Library for C++ Let's join forces! 72
  • 146. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 146/157 We really need physical units and dimensional analysis support in the C++ Standard Library • C++ community and industry really need it • Great opportunity to learn C++20 • An interesting and hard challenge to solve ;-) 4Developers 2019 | Implementing Physical Units Library for C++ Let's join forces! WHY TO JOIN? 72
  • 147. 8.04.2019 std::units file:///C:/repos/cppTrainings/build/out/units/units.html#149 147/157 We really need physical units and dimensional analysis support in the C++ Standard Library • C++ community and industry really need it • Great opportunity to learn C++20 • An interesting and hard challenge to solve ;-) 4Developers 2019 | Implementing Physical Units Library for C++ Let's join forces! WHY TO JOIN? Please, help... 72