SlideShare a Scribd company logo
1 of 184
Download to read offline
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 1/184
Mateusz Pusz
May 25, 2019
Implementing a Physical Units
Library for C++
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 2/184
A famous motivating example
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 3/184
• Robotic space probe launched by NASA on
December 11, 1998
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
The Mars Climate Orbiter
3
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 4/184
• Robotic space probe launched by NASA on
December 11, 1998
• Project costs: $327.6 million
– spacecra development: $193.1 million
– launching it: $91.7 million
– mission operations: $42.8 million
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
The Mars Climate Orbiter
3
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 5/184
• Robotic space probe launched by NASA on
December 11, 1998
• Project costs: $327.6 million
– spacecra development: $193.1 million
– launching it: $91.7 million
– mission operations: $42.8 million
• Mars Climate Orbiter began the planned
orbital insertion maneuver on September 23,
1999 at 09:00:46 UTC
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
The Mars Climate Orbiter
3
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 6/184
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 7/184
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 8/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
The Mars Climate Orbiter
6
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 9/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
What went wrong?
7
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 10/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
What went wrong?
7
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 11/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
What went wrong?
7
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 12/184
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 13/184
Why do I care?
ANOTHER EXAMPLE
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 14/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
A long time ago in a galaxy far far away...
10
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 15/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
A long time ago in a galaxy far far away...
10
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 16/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Tactical Flight Computer
11
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 17/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Tactical Flight Computer
12
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 18/184
void DistanceBearing(double lat1, double lon1,
double lat2, double lon2,
double *Distance, double *Bearing);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
What is the correct order?
13
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 19/184
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);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
What is the correct order?
13
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 20/184
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);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
What is the correct order?
13
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 21/184
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);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
double - an ultimate type to express quantity
14
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 22/184
// 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)));
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
We shouldn't write the code like that anymore
15
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 23/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
DID YOU EVER HAVE TO WRITE THE CODE THIS WAY?
16
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 24/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Why do we write our code this way?
17
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 25/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Why do we write our code this way?
17
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 26/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Why do we write our code this way?
17
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 27/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Why do we write our code this way?
17
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 28/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Why do we write our code this way?
Let's do something about that!
17
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 29/184
C++ CoreHard Spring 2019 | Implementing a 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
18
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 30/184
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 31/184
/* velocity */ avg_speed(/* length */ distance, /* time */ duration)
{
return distance / duration;
}
const auto kmph = avg_speed(/* 220 km */, /* 2 hours */);
std::cout << /* kmph */ << " km/hn";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 32/184
/* 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";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 33/184
/* 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 34/184
/* 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 35/184
/* 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 36/184
/* 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())
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
19
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 37/184
• Boost.Units
– authors: Steven Watanabe, Matthias C. Schabel
– https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Existing solutions
20
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 38/184
• Boost.Units
– authors: Steven Watanabe, Matthias C. Schabel
– https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html
• Units
– author: Nic Holthaus
– https://github.com/nholthaus/units
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Existing solutions
20
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 39/184
#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>
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
21
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 40/184
#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;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
21
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 41/184
#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;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
21
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 42/184
#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);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
21
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 43/184
#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);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
21
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 44/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{
return d / t;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
22
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 45/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{
return d / t;
}
const auto v = avg_speed(bu::quantity<bu::si::length>(220 * bu::si::kilo * bu::si::meters),
bu::quantity<bu::si::time>(2 * hours));
using kilometers_per_hour = bu::divide_typeof_helper<length_kilometer, time_hour>::type;
bu::quantity<kilometers_per_hour> kmph(v);
std::cout << kmph.value() << " km/hn";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
22
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 46/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{
return d / t;
}
const auto v = avg_speed(bu::quantity<bu::si::length>(220 * bu::si::kilo * bu::si::meters),
bu::quantity<bu::si::time>(2 * hours));
using kilometers_per_hour = bu::divide_typeof_helper<length_kilometer, time_hour>::type;
bu::quantity<kilometers_per_hour> kmph(v);
std::cout << kmph.value() << " km/hn";
const auto v = avg_speed(bu::quantity<bu::si::length>(140 * miles),
bu::quantity<bu::si::time>(2 * hours));
using miles_per_hour = bu::divide_typeof_helper<length_mile, time_hour>::type;
bu::quantity<miles_per_hour> mph(v);
std::cout << mph.value() << " mphn";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
22
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 47/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{
return d / t;
}
const auto v = avg_speed(bu::quantity<bu::si::length>(220 * bu::si::kilo * bu::si::meters),
bu::quantity<bu::si::time>(2 * hours));
using kilometers_per_hour = bu::divide_typeof_helper<length_kilometer, time_hour>::type;
bu::quantity<kilometers_per_hour> kmph(v);
std::cout << kmph.value() << " km/hn";
const auto v = avg_speed(bu::quantity<bu::si::length>(140 * miles),
bu::quantity<bu::si::time>(2 * hours));
using miles_per_hour = bu::divide_typeof_helper<length_mile, time_hour>::type;
bu::quantity<miles_per_hour> mph(v);
std::cout << mph.value() << " mphn";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
Works, but runtime does unnecessary operations, and we may loose some
bits of information while doing that
22
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 48/184
• Too generic
template<typename Length, typename Time>
constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t)
{ return d / t; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
23
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 49/184
• 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; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
23
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 50/184
• 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; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
23
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 51/184
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);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
24
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 52/184
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";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
24
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 53/184
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";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Toy example
24
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 54/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Summary
PROS
25
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 55/184
• 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)
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Boost.Units: Summary
PROS CONS
25
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 56/184
#include "units.h"
using namespace units::literals;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
26
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 57/184
#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;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
26
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 58/184
#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;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
26
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 59/184
#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>>>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
26
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 60/184
#include "units.h"
using namespace units::literals;
template<typename Length, typename Time,
typename = std::enable_if_t<units::traits::is_length_unit<Length>::value &&
units::traits::is_time_unit<Time>::value>>
constexpr auto avg_speed(Length d, Time t)
{
const auto v = d / t;
static_assert(units::traits::is_velocity_unit<decltype(v)>::value);
return v;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
27
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 61/184
#include "units.h"
using namespace units::literals;
template<typename Length, typename Time,
typename = std::enable_if_t<units::traits::is_length_unit<Length>::value &&
units::traits::is_time_unit<Time>::value>>
constexpr auto avg_speed(Length d, Time t)
{
const auto v = d / t;
static_assert(units::traits::is_velocity_unit<decltype(v)>::value);
return v;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
Using SFINAE in every single function template working with units is probably
too complicated or time consuming for an average user of the library
27
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 62/184
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
28
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 63/184
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";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
28
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 64/184
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";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
28
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 65/184
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
units::length::kilometer_t d(220);
units::time::hour_t t(2);
const auto kmph = avg_speed(d, t);
std::cout << kmph.value() << " km/hn";
units::length::mile_t d(140);
units::time::hour_t t(2);
const auto mph = avg_speed(d, t);
std::cout << mph.value() << " mphn";
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
29
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 66/184
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t);
units::length::kilometer_t d(220);
units::time::hour_t t(2);
const auto kmph = avg_speed(d, t);
std::cout << kmph.value() << " km/hn";
units::length::mile_t d(140);
units::time::hour_t t(2);
const auto mph = avg_speed(d, t);
std::cout << mph.value() << " mphn";
meter is a unit, not a quantity!
-- Walter Brown
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Toy example
29
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 67/184
• Single header file units.h
• The conversions between units are defined as
ratios at compile time
• UDL support
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Summary
PROS
30
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 68/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units: Summary
PROS CONS
30
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 69/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
ISSUES WITH CURRENT SOLUTIONS
31
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 70/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{ return d * t; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Boost.Units
32
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 71/184
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 =
...
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Boost.Units
GCC-8
32
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 72/184
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;
~~^~~
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Boost.Units
GCC-8 (CONTINUED)
33
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 73/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{ return d * t; }
error: no viable conversion from returned value of type 'quantity<unit<list<[...], list<dim<[...],
static_rational<1, [...]>>, [...]>>, [...]>, [...]>' to function return type 'quantity<unit<list<[...], list<dim<[...],
static_rational<-1, [...]>>, [...]>>, [...]>, [...]>'
return d * t;
^~~~~
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Boost.Units
CLANG-7
34
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 74/184
constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t)
{ return d * t; }
error: no viable conversion from returned value of type 'quantity<unit<list<[...], list<dim<[...],
static_rational<1, [...]>>, [...]>>, [...]>, [...]>' to function return type 'quantity<unit<list<[...], list<dim<[...],
static_rational<-1, [...]>>, [...]>>, [...]>, [...]>'
return d * t;
^~~~~
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Boost.Units
CLANG-7
Sometimes shorter error message is not necessary better ;-)
34
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 75/184
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t) { return d * t; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Units
35
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 76/184
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.");
^~~~~~
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Units
GCC-8
35
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 77/184
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.");
^~~~~~
C++ CoreHard Spring 2019 | Implementing a 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
35
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 78/184
template<typename Length, typename Time>
constexpr auto avg_speed(Length d, Time t) { return d * t; }
error: static_assert failed due to requirement 'traits::is_convertible_unit<unit<ratio<3600000, 1>, base_unit<ratio<1, 1>,
ratio<0, 1>, ratio<1, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1> >, ratio<0, 1>,
ratio<0, 1> >, unit<ratio<5, 18>, base_unit<ratio<1, 1>, ratio<0, 1>, ratio<-1, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>,
ratio<0, 1>, ratio<0, 1>, ratio<0, 1> >, ratio<0, 1>, ratio<0, 1> > >::value' "Units are not compatible."
static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible.");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Compilation: Units
CLANG-7
36
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 79/184
• For most template metaprogramming libraries compile-time errors are rare
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
A need to modernize our toolbox
37
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 80/184
• For most template metaprogramming libraries compile-time errors are rare
• It is expected that engineers working with physical units library will experience compile-time errors
very o en
– generating compile-time errors for invalid calculation is the main reason to create such a library
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
A need to modernize our toolbox
37
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 81/184
• For most template metaprogramming libraries compile-time errors are rare
• It is expected that engineers working with physical units library will experience compile-time errors
very o en
– generating compile-time errors for invalid calculation is the main reason to create such a library
In case of the physical units library we have to rethink the way we
do template metaprogramming!
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
A need to modernize our toolbox
37
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 82/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Boost.Units
38
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 83/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Boost.Units
38
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 84/184
Breakpoint 1, 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;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Boost.Units
39
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 85/184
(gdb) ptype d
type = class boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension,
boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, 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, 1> >, boost::units::dimensionless_type>,
boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >,
boost::units::dimensionless_type>, boost::units::list<boost::units::scale_list_dim<boost::units::scale<10, static_rational<3> > >,
boost::units::dimensionless_type> > >, void>, double> [with Unit = boost::units::unit<boost::units::list<boost::units::dim
<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>,
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, 1> >,
boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::length_base_dimension,
boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::scale_list_dim
<boost::units::scale<10, static_rational<3> > >, boost::units::dimensionless_type> > >, void>, Y = double] {
...
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Boost.Units
40
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 86/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Units
41
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 87/184
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Units
41
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 88/184
Breakpoint 1, 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;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Units
42
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 89/184
(gdb) ptype d
type = class units::unit_t<units::unit<std::ratio<1000, 1>, units::unit<std::ratio<1, 1>, units::base_unit<std::ratio<1, 1>,
std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>,
std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, double, units::linear_scale>
[with Units = units::unit<std::ratio<1000, 1>, units::unit<std::ratio<1, 1>, units::base_unit<std::ratio<1, 1>, std::ratio<0, 1>,
std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1> >,
std::ratio<0, 1>, std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, T = double] : public units::linear_scale<T>,
private units::detail::_unit_t {
...
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
User experience: Debugging: Units
43
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 90/184
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...
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Macros omnipresence: Boost.Units
44
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 91/184
#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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Macros omnipresence: Units
45
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 92/184
• Adding derived dimensions is pretty easy in all the libraries
• Adding base dimensions is hard or nearly impossible
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Extensibility
46
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 93/184
• 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)
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Extensibility
BOOST.UNITS
46
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 94/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Extensibility
UNITS
47
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 95/184
C++ CoreHard Spring 2019 | Implementing a 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
48
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 96/184
• The best possible user experience
– compiler errors
– debugging
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Requirements
49
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 97/184
• The best possible user experience
– compiler errors
– debugging
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Requirements
49
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 98/184
• The best possible user experience
– compiler errors
– debugging
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
• No macros in the user interface
• No external dependencies
• Easy extensibility
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Requirements
49
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 99/184
• The best possible user experience
– compiler errors
– debugging
• Safety and performance
– strong types
– template metaprogramming
– constexpr all the things
• No macros in the user interface
• No external dependencies
• Easy extensibility
• Possibility to be standardized as a freestanding part of the C++ Standard Library
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Requirements
49
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 100/184
• units::dimension - a type-list-like type that stores an ordered list of exponents of one or more base
dimensions
template<typename... Exponents>
struct dimension;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
50
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 101/184
• units::dimension - a type-list-like type that stores an ordered list of exponents of one or more base
dimensions
template<typename... Exponents>
struct dimension;
• units::exp - a base dimension and its exponent in a derived dimension
template<typename BaseDimension, int Value>
struct exp {
using dimension = BaseDimension;
static constexpr int value = Value;
};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
50
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 102/184
• BaseDimension is a unique sortable compile-time value
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
51
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 103/184
• BaseDimension is a unique sortable compile-time value
template<int UniqueValue>
using dim_id = std::integral_constant<int, UniqueValue>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
51
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 104/184
• 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> {};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
EXAMPLE
51
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 105/184
• 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> {};
C++ CoreHard Spring 2019 | Implementing a 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
51
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 106/184
• Allow non-union class types to appear in non-type template parameters
• Require that types used as such, have strong structural equality
– a type T is having strong structural equality if each subobject recursively has defaulted == and none
of the subobjects are floating point types
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
P0732 P1185 Class Types in Non-Type Template Parameters
52
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 107/184
• Allow non-union class types to appear in non-type template parameters
• Require that types used as such, have strong structural equality
– a type T is having strong structural equality if each subobject recursively has defaulted == and none
of the subobjects are floating point types
template<fixed_string Id>
class entity { /* ... */ };
entity<"hello"> e;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
P0732 P1185 Class Types in Non-Type Template Parameters
52
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 108/184
• 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;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++20 Exponent and Base Dimension
53
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 109/184
• 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");
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++20 Exponent and Base Dimension
EXAMPLE
53
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 110/184
• 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");
C++ CoreHard Spring 2019 | Implementing a 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
53
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 111/184
• We can express velocity in the following way
dimension<exp<base_dim_length, 1>, exp<base_dim_time, -1>>
– improves user experience
– as short as possible template instantiations
– easy to understand by every engineer
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
54
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 112/184
• We can express velocity in the following way
dimension<exp<base_dim_length, 1>, exp<base_dim_time, -1>>
– improves user experience
– as short as possible template instantiations
– easy to understand by every engineer
• The same type expected for both operations
constexpr auto v1 = 1_m / 1_s;
constexpr auto v2 = 2 / 2_s * 1_m;
static_assert(std::is_same<decltype(v1), decltype(v2)>);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions
PROBLEM
54
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 113/184
template<typename... Exponents>
struct make_dimension {
using type = /* unspecified */;
};
template<typename... Exponents>
using make_dimension_t = make_dimension<Exponents...>::type;
• Provides unique ordering for contained base dimensions
• Aggregates two arguments of the same base dimension but di erent exponents
• Eliminates two arguments of the same base dimension and with opposite equal exponents
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions: make_dimension factory helper
55
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 114/184
template<typename... Exponents>
struct make_dimension {
using type = /* unspecified */;
};
template<typename... Exponents>
using make_dimension_t = make_dimension<Exponents...>::type;
• Provides unique ordering for contained base dimensions
• Aggregates two arguments of the same base dimension but di erent exponents
• Eliminates two arguments of the same base dimension and with opposite equal exponents
• To form a velocity
make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Dimensions: make_dimension factory helper
EXAMPLE
55
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 115/184
• unit - the unit of a specific physical dimension
template<typename Dimension, typename Ratio = std::ratio<1>>
struct unit {
using dimension = Dimension;
using ratio = Ratio;
};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units
56
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 116/184
• unit - the unit of a specific physical dimension
template<typename Dimension, typename Ratio = std::ratio<1>>
struct unit {
using dimension = Dimension;
using ratio = Ratio;
};
To express meter
unit<dimension_length>
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Units
EXAMPLE
56
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 117/184
• quantity - the amount of a specific dimension expressed in a specific unit of that dimension
template<typename Dimension, typename Unit, typename Rep>
class quantity;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Quantities
57
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 118/184
• quantity - the amount of a specific dimension expressed in a specific unit of that dimension
template<typename Dimension, typename Unit, typename Rep>
class quantity;
• Interface similar to std::chrono::duration + additional member functions
– multiplication of 2 quantities with di erent dimensions
1_kmph * 1_h == 1_km
– division of 2 quantities of di erent dimensions
1_km / 1_h == 1_kmph
– division of a scalar with a quantity
1 / 1_s == 1_Hz
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Quantities
57
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 119/184
• quantity - the amount of a specific dimension expressed in a specific unit of that dimension
template<typename Dimension, typename Unit, typename Rep>
class quantity;
template<typename Unit = meter_per_second, typename Rep = double>
using velocity = quantity<dimension_velocity, Unit, Rep>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Quantities
EXAMPLE
58
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 120/184
What is the quantity? An absolute or a relative value?
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Important design question
59
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 121/184
What is the quantity? An absolute or a relative value?
• For most dimensions only relative values have sense
– Where is absolute 123 meters?
– If I am sitting in a moving train is my velocity == 0?
– Is my velocity == 0 when the train stops?
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Important design question
59
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 122/184
What is the quantity? An absolute or a relative value?
• For most dimensions only relative values have sense
– Where is absolute 123 meters?
– If I am sitting in a moving train is my velocity == 0?
– Is my velocity == 0 when the train stops?
• For some dimensions absolute values are really needed
– temperature
– time
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Important design question
59
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 123/184
1 Generic programming
2 Compile-time errors
3 Debugging
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Struggling with the user experience
60
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 124/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Do you remember that?
BOOST.UNITS
UNITS
61
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 125/184
#include <boost/units/is_quantity_of_dimension.hpp>
template<typename Quantity, typename Dimension>
concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++ Concepts to the rescue
BOOST.UNITS
62
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 126/184
#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>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++ Concepts to the rescue
BOOST.UNITS
62
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 127/184
#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; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++ Concepts to the rescue
BOOST.UNITS
62
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 128/184
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;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++ Concepts to the rescue
UNITS
63
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 129/184
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; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++ Concepts to the rescue
UNITS
63
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 130/184
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; }
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++ Concepts to the rescue
UNITS
Concepts can also be used in places where regular template argument
deduction does not work (i.e. return types, class template parameters, etc).
63
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 131/184
All template types are heavily embraced with concepts
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
I lied a bit ;-)
64
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 132/184
• TypeList
• Scalar
• Ratio
• Exponent
• Dimension
• Unit
• Quantity
All template types are heavily embraced with concepts
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
I lied a bit ;-)
UNITS ENGINE CONCEPTS
64
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 133/184
• TypeList
• Scalar
• Ratio
• Exponent
• Dimension
• Unit
• Quantity
• Length
• Time
• Frequency
• Velocity
• ...
template<typename T>
concept Velocity = Quantity<T> &&
std::Same<typename T::dimension, dimension_velocity>;
All template types are heavily embraced with concepts
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
I lied a bit ;-)
UNITS ENGINE CONCEPTS PREDEFINED QUANTITIES CONCEPTS
64
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 134/184
• 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>>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Type aliases are great (but not for users)
65
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 135/184
• 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Type aliases are great (but not for users)
65
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 136/184
• 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>]
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Type aliases are great (but not for users)
65
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 137/184
• 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>]
C++ CoreHard Spring 2019 | Implementing a 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 :-(
65
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 138/184
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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Inheritance to the rescue
66
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 139/184
Velocity auto v = 10_m / 2_s;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting problem
67
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 140/184
Velocity auto v = 10_m / 2_s;
template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2>
constexpr Quantity operator/(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting problem
67
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 141/184
Velocity auto v = 10_m / 2_s;
template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2>
constexpr Quantity operator/(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting problem
How to form dimension_velocity child class from division of
dimension_length by dimension_time?
67
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 142/184
template<typename T>
struct type_identity { using type = T; };
template<typename T>
using type_identity_t = type_identity<T>::type;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
P0887 The identity metafunction
68
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 143/184
template<typename BaseType>
struct upcast_base {
using base_type = BaseType;
};
template<Exponent... Es>
struct dimension : upcast_base<dimension<Es...>> {};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting facility
BASE CLASS
69
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 144/184
template<typename BaseType>
struct upcast_base {
using base_type = BaseType;
};
template<Exponent... Es>
struct dimension : upcast_base<dimension<Es...>> {};
template<typename T>
concept Upcastable =
requires {
typename T::base_type;
} &&
std::DerivedFrom<T, upcast_base<typename T::base_type>>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting facility
BASE CLASS
UPCASTABLE
69
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 145/184
template<Upcastable T>
using upcast_from = T::base_type;
template<Upcastable T>
using upcast_to = std::type_identity<T>;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting facility
HELPER ALIASES
70
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 146/184
template<Upcastable T>
using upcast_from = T::base_type;
template<Upcastable T>
using upcast_to = std::type_identity<T>;
template<Upcastable T>
struct upcasting_traits : upcast_to<T> {};
template<Upcastable T>
using upcasting_traits_t = upcasting_traits<T>::type;
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting facility
HELPER ALIASES
UPCASTING TRAITS
70
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 147/184
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>> {};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting dimension
71
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 148/184
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>> {};
template<>
struct upcasting_traits<upcast_from<dimension_velocity>> : upcast_to<dimension_velocity> {};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting dimension
71
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 149/184
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>> {};
template<>
struct upcasting_traits<upcast_from<dimension_velocity>> : upcast_to<dimension_velocity> {};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting dimension
Help needed: How to automate the last line?
71
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 150/184
[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>]
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting facility
BEFORE
72
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 151/184
[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>
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Upcasting facility
BEFORE
AFTER
72
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 152/184
template<Dimension D, Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != quantity<D, U2, Rep2>(0));
// ...
}
};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Contracts
73
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 153/184
template<Dimension D, Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar 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
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Contracts
73
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 154/184
template<Dimension D, Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar 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));
// ...
}
};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Contracts
74
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 155/184
template<Dimension D, Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
// ...
}
};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Contracts
75
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 156/184
template<Dimension D, Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs)
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
// ...
}
};
C++ CoreHard Spring 2019 | Implementing a 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
75
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 157/184
template<Dimension D, Unit U, Scalar Rep>
requires std::Same<D, typename U::dimension>
class quantity {
public:
template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2>
[[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs,
const quantity<D, U2, Rep2>& rhs) [[expects: rhs != quantity<D, U2, Rep2>(0)]]
{
// ...
}
};
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
C++20 Contracts
76
25.05.2019 Implementing a Physical Units Library for C++
file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 158/184
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
{
return d / t;
}
C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++
Toy example
77
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++

More Related Content

Similar to Implementing a Physical Units Library for C++

Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJIntroduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
meharikiros2
 
MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0
MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0
MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0
Thomas Conté
 

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

Streaming Topic Model Training and Inference with Apache Flink
Streaming Topic Model Training and Inference with Apache FlinkStreaming Topic Model Training and Inference with Apache Flink
Streaming Topic Model Training and Inference with Apache Flink
 
Introduction-to-C-Part-1.pptx
Introduction-to-C-Part-1.pptxIntroduction-to-C-Part-1.pptx
Introduction-to-C-Part-1.pptx
 
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJIntroduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
Introduction-to-C-Part-1 JSAHSHAHSJAHSJAHSJHASJ
 
Airbus: Innovating the Future of Flight
Airbus: Innovating the Future of FlightAirbus: Innovating the Future of Flight
Airbus: Innovating the Future of Flight
 
Recap of de code 2019
Recap of de code 2019Recap of de code 2019
Recap of de code 2019
 
How to deploy machine learning models into production
How to deploy machine learning models into productionHow to deploy machine learning models into production
How to deploy machine learning models into production
 
FHIR-first development of healthcare applications
FHIR-first development of healthcare applicationsFHIR-first development of healthcare applications
FHIR-first development of healthcare applications
 
Introduction-to-C-Part-1 (1).doc
Introduction-to-C-Part-1 (1).docIntroduction-to-C-Part-1 (1).doc
Introduction-to-C-Part-1 (1).doc
 
Daho.am meetup kubernetes evolution @abi
Daho.am meetup   kubernetes evolution @abiDaho.am meetup   kubernetes evolution @abi
Daho.am meetup kubernetes evolution @abi
 
ANSI ISO C Professional Programmer S Handbook
ANSI ISO C   Professional Programmer S HandbookANSI ISO C   Professional Programmer S Handbook
ANSI ISO C Professional Programmer S Handbook
 
C++ helps you to format the I/O operations like determining the number of dig...
C++ helps you to format the I/O operations like determining the number of dig...C++ helps you to format the I/O operations like determining the number of dig...
C++ helps you to format the I/O operations like determining the number of dig...
 
Bluemix hadoop beginners Guide part I
Bluemix hadoop beginners Guide part IBluemix hadoop beginners Guide part I
Bluemix hadoop beginners Guide part I
 
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantEffective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variant
 
Cloud-Native Application and Kubernetes
Cloud-Native Application and KubernetesCloud-Native Application and Kubernetes
Cloud-Native Application and Kubernetes
 
C++ was developed by Bjarne Stroustrup, as an extension to the C language. cp...
C++ was developed by Bjarne Stroustrup, as an extension to the C language. cp...C++ was developed by Bjarne Stroustrup, as an extension to the C language. cp...
C++ was developed by Bjarne Stroustrup, as an extension to the C language. cp...
 
MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0
MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0
MS Day EPITA 2010: Visual Studio 2010 et Framework .NET 4.0
 
Assisted code review with source{d} lookout
Assisted code review with source{d} lookoutAssisted code review with source{d} lookout
Assisted code review with source{d} lookout
 
Cloud Foundry for Data Science
Cloud Foundry for Data ScienceCloud Foundry for Data Science
Cloud Foundry for Data Science
 
use case ibm k8s_service+devops
use case ibm k8s_service+devopsuse case ibm k8s_service+devops
use case ibm k8s_service+devops
 
給 RD 的 Kubernetes 初體驗 (GDG Cloud KH 2019-08 version)
給 RD 的 Kubernetes 初體驗 (GDG Cloud KH 2019-08 version) 給 RD 的 Kubernetes 初體驗 (GDG Cloud KH 2019-08 version)
給 RD 的 Kubernetes 初體驗 (GDG Cloud KH 2019-08 version)
 

More from Mateusz Pusz

More from Mateusz Pusz (11)

Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low Latency
 
Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++
 
C++11 Was Only the Beginning
C++11 Was Only the BeginningC++11 Was Only the Beginning
C++11 Was Only the Beginning
 
C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?
 
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantEffective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variant
 
Beyond C++17
Beyond C++17Beyond C++17
Beyond C++17
 
Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low Latency
 
Small Lie in Big O
Small Lie in Big OSmall Lie in Big O
Small Lie in Big O
 
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nailstd::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
 

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Recently uploaded (20)

Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 

Implementing a Physical Units Library for C++

  • 1. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 1/184 Mateusz Pusz May 25, 2019 Implementing a Physical Units Library for C++
  • 2. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 2/184 A famous motivating example
  • 3. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 3/184 • Robotic space probe launched by NASA on December 11, 1998 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ The Mars Climate Orbiter 3
  • 4. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 4/184 • Robotic space probe launched by NASA on December 11, 1998 • Project costs: $327.6 million – spacecra development: $193.1 million – launching it: $91.7 million – mission operations: $42.8 million C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ The Mars Climate Orbiter 3
  • 5. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 5/184 • Robotic space probe launched by NASA on December 11, 1998 • Project costs: $327.6 million – spacecra development: $193.1 million – launching it: $91.7 million – mission operations: $42.8 million • Mars Climate Orbiter began the planned orbital insertion maneuver on September 23, 1999 at 09:00:46 UTC C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ The Mars Climate Orbiter 3
  • 6. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 6/184
  • 7. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 7/184
  • 8. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 8/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ The Mars Climate Orbiter 6
  • 9. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 9/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ What went wrong? 7
  • 10. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 10/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ What went wrong? 7
  • 11. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 11/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ What went wrong? 7
  • 12. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 12/184
  • 13. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 13/184 Why do I care? ANOTHER EXAMPLE
  • 14. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 14/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ A long time ago in a galaxy far far away... 10
  • 15. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 15/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ A long time ago in a galaxy far far away... 10
  • 16. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 16/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Tactical Flight Computer 11
  • 17. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 17/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Tactical Flight Computer 12
  • 18. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 18/184 void DistanceBearing(double lat1, double lon1, double lat2, double lon2, double *Distance, double *Bearing); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ What is the correct order? 13
  • 19. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 19/184 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); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ What is the correct order? 13
  • 20. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 20/184 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); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ What is the correct order? 13
  • 21. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 21/184 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); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ double - an ultimate type to express quantity 14
  • 22. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 22/184 // 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))); } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ We shouldn't write the code like that anymore 15
  • 23. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 23/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ DID YOU EVER HAVE TO WRITE THE CODE THIS WAY? 16
  • 24. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 24/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Why do we write our code this way? 17
  • 25. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 25/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Why do we write our code this way? 17
  • 26. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 26/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Why do we write our code this way? 17
  • 27. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 27/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Why do we write our code this way? 17
  • 28. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 28/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Why do we write our code this way? Let's do something about that! 17
  • 29. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 29/184 C++ CoreHard Spring 2019 | Implementing a 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 18
  • 30. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 30/184 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 31. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 31/184 /* velocity */ avg_speed(/* length */ distance, /* time */ duration) { return distance / duration; } const auto kmph = avg_speed(/* 220 km */, /* 2 hours */); std::cout << /* kmph */ << " km/hn"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 32. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 32/184 /* 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"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 33. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 33/184 /* 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 34. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 34/184 /* 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 35. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 35/184 /* 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 36. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 36/184 /* 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()) C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 19
  • 37. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 37/184 • Boost.Units – authors: Steven Watanabe, Matthias C. Schabel – https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Existing solutions 20
  • 38. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 38/184 • Boost.Units – authors: Steven Watanabe, Matthias C. Schabel – https://www.boost.org/doc/libs/1_69_0/doc/html/boost_units.html • Units – author: Nic Holthaus – https://github.com/nholthaus/units C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Existing solutions 20
  • 39. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 39/184 #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> C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 21
  • 40. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 40/184 #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; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 21
  • 41. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 41/184 #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; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 21
  • 42. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 42/184 #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); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 21
  • 43. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 43/184 #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); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 21
  • 44. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 44/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d / t; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 22
  • 45. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 45/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d / t; } const auto v = avg_speed(bu::quantity<bu::si::length>(220 * bu::si::kilo * bu::si::meters), bu::quantity<bu::si::time>(2 * hours)); using kilometers_per_hour = bu::divide_typeof_helper<length_kilometer, time_hour>::type; bu::quantity<kilometers_per_hour> kmph(v); std::cout << kmph.value() << " km/hn"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 22
  • 46. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 46/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d / t; } const auto v = avg_speed(bu::quantity<bu::si::length>(220 * bu::si::kilo * bu::si::meters), bu::quantity<bu::si::time>(2 * hours)); using kilometers_per_hour = bu::divide_typeof_helper<length_kilometer, time_hour>::type; bu::quantity<kilometers_per_hour> kmph(v); std::cout << kmph.value() << " km/hn"; const auto v = avg_speed(bu::quantity<bu::si::length>(140 * miles), bu::quantity<bu::si::time>(2 * hours)); using miles_per_hour = bu::divide_typeof_helper<length_mile, time_hour>::type; bu::quantity<miles_per_hour> mph(v); std::cout << mph.value() << " mphn"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 22
  • 47. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 47/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d / t; } const auto v = avg_speed(bu::quantity<bu::si::length>(220 * bu::si::kilo * bu::si::meters), bu::quantity<bu::si::time>(2 * hours)); using kilometers_per_hour = bu::divide_typeof_helper<length_kilometer, time_hour>::type; bu::quantity<kilometers_per_hour> kmph(v); std::cout << kmph.value() << " km/hn"; const auto v = avg_speed(bu::quantity<bu::si::length>(140 * miles), bu::quantity<bu::si::time>(2 * hours)); using miles_per_hour = bu::divide_typeof_helper<length_mile, time_hour>::type; bu::quantity<miles_per_hour> mph(v); std::cout << mph.value() << " mphn"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example Works, but runtime does unnecessary operations, and we may loose some bits of information while doing that 22
  • 48. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 48/184 • Too generic template<typename Length, typename Time> constexpr auto avg_speed(bu::quantity<Length> d, bu::quantity<Time> t) { return d / t; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 23
  • 49. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 49/184 • 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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 23
  • 50. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 50/184 • 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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 23
  • 51. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 51/184 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); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 24
  • 52. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 52/184 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"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 24
  • 53. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 53/184 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"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Toy example 24
  • 54. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 54/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Summary PROS 25
  • 55. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 55/184 • 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) C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Boost.Units: Summary PROS CONS 25
  • 56. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 56/184 #include "units.h" using namespace units::literals; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 26
  • 57. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 57/184 #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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 26
  • 58. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 58/184 #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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 26
  • 59. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 59/184 #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>>>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 26
  • 60. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 60/184 #include "units.h" using namespace units::literals; template<typename Length, typename Time, typename = std::enable_if_t<units::traits::is_length_unit<Length>::value && units::traits::is_time_unit<Time>::value>> constexpr auto avg_speed(Length d, Time t) { const auto v = d / t; static_assert(units::traits::is_velocity_unit<decltype(v)>::value); return v; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 27
  • 61. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 61/184 #include "units.h" using namespace units::literals; template<typename Length, typename Time, typename = std::enable_if_t<units::traits::is_length_unit<Length>::value && units::traits::is_time_unit<Time>::value>> constexpr auto avg_speed(Length d, Time t) { const auto v = d / t; static_assert(units::traits::is_velocity_unit<decltype(v)>::value); return v; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example Using SFINAE in every single function template working with units is probably too complicated or time consuming for an average user of the library 27
  • 62. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 62/184 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 28
  • 63. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 63/184 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"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 28
  • 64. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 64/184 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"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 28
  • 65. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 65/184 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); units::length::kilometer_t d(220); units::time::hour_t t(2); const auto kmph = avg_speed(d, t); std::cout << kmph.value() << " km/hn"; units::length::mile_t d(140); units::time::hour_t t(2); const auto mph = avg_speed(d, t); std::cout << mph.value() << " mphn"; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 29
  • 66. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 66/184 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t); units::length::kilometer_t d(220); units::time::hour_t t(2); const auto kmph = avg_speed(d, t); std::cout << kmph.value() << " km/hn"; units::length::mile_t d(140); units::time::hour_t t(2); const auto mph = avg_speed(d, t); std::cout << mph.value() << " mphn"; meter is a unit, not a quantity! -- Walter Brown C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Toy example 29
  • 67. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 67/184 • Single header file units.h • The conversions between units are defined as ratios at compile time • UDL support C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Summary PROS 30
  • 68. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 68/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units: Summary PROS CONS 30
  • 69. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 69/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ ISSUES WITH CURRENT SOLUTIONS 31
  • 70. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 70/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d * t; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Boost.Units 32
  • 71. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 71/184 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 = ... C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Boost.Units GCC-8 32
  • 72. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 72/184 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; ~~^~~ C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Boost.Units GCC-8 (CONTINUED) 33
  • 73. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 73/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d * t; } error: no viable conversion from returned value of type 'quantity<unit<list<[...], list<dim<[...], static_rational<1, [...]>>, [...]>>, [...]>, [...]>' to function return type 'quantity<unit<list<[...], list<dim<[...], static_rational<-1, [...]>>, [...]>>, [...]>, [...]>' return d * t; ^~~~~ C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Boost.Units CLANG-7 34
  • 74. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 74/184 constexpr bu::quantity<bu::si::velocity> avg_speed(bu::quantity<bu::si::length> d, bu::quantity<bu::si::time> t) { return d * t; } error: no viable conversion from returned value of type 'quantity<unit<list<[...], list<dim<[...], static_rational<1, [...]>>, [...]>>, [...]>, [...]>' to function return type 'quantity<unit<list<[...], list<dim<[...], static_rational<-1, [...]>>, [...]>>, [...]>, [...]>' return d * t; ^~~~~ C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Boost.Units CLANG-7 Sometimes shorter error message is not necessary better ;-) 34
  • 75. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 75/184 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { return d * t; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Units 35
  • 76. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 76/184 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."); ^~~~~~ C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Units GCC-8 35
  • 77. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 77/184 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."); ^~~~~~ C++ CoreHard Spring 2019 | Implementing a 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 35
  • 78. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 78/184 template<typename Length, typename Time> constexpr auto avg_speed(Length d, Time t) { return d * t; } error: static_assert failed due to requirement 'traits::is_convertible_unit<unit<ratio<3600000, 1>, base_unit<ratio<1, 1>, ratio<0, 1>, ratio<1, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1> >, ratio<0, 1>, ratio<0, 1> >, unit<ratio<5, 18>, base_unit<ratio<1, 1>, ratio<0, 1>, ratio<-1, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1>, ratio<0, 1> >, ratio<0, 1>, ratio<0, 1> > >::value' "Units are not compatible." static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible."); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Compilation: Units CLANG-7 36
  • 79. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 79/184 • For most template metaprogramming libraries compile-time errors are rare C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ A need to modernize our toolbox 37
  • 80. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 80/184 • For most template metaprogramming libraries compile-time errors are rare • It is expected that engineers working with physical units library will experience compile-time errors very o en – generating compile-time errors for invalid calculation is the main reason to create such a library C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ A need to modernize our toolbox 37
  • 81. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 81/184 • For most template metaprogramming libraries compile-time errors are rare • It is expected that engineers working with physical units library will experience compile-time errors very o en – generating compile-time errors for invalid calculation is the main reason to create such a library In case of the physical units library we have to rethink the way we do template metaprogramming! C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ A need to modernize our toolbox 37
  • 82. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 82/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Boost.Units 38
  • 83. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 83/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Boost.Units 38
  • 84. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 84/184 Breakpoint 1, 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; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Boost.Units 39
  • 85. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 85/184 (gdb) ptype d type = class boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, 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, 1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::scale_list_dim<boost::units::scale<10, static_rational<3> > >, boost::units::dimensionless_type> > >, void>, double> [with Unit = boost::units::unit<boost::units::list<boost::units::dim <boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, 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, 1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, boost::units::list<boost::units::scale_list_dim <boost::units::scale<10, static_rational<3> > >, boost::units::dimensionless_type> > >, void>, Y = double] { ... C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Boost.Units 40
  • 86. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 86/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Units 41
  • 87. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 87/184 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Units 41
  • 88. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 88/184 Breakpoint 1, 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; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Units 42
  • 89. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 89/184 (gdb) ptype d type = class units::unit_t<units::unit<std::ratio<1000, 1>, units::unit<std::ratio<1, 1>, units::base_unit<std::ratio<1, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, double, units::linear_scale> [with Units = units::unit<std::ratio<1000, 1>, units::unit<std::ratio<1, 1>, units::base_unit<std::ratio<1, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1>, std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, std::ratio<0, 1>, std::ratio<0, 1> >, T = double] : public units::linear_scale<T>, private units::detail::_unit_t { ... C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ User experience: Debugging: Units 43
  • 90. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 90/184 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... C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Macros omnipresence: Boost.Units 44
  • 91. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 91/184 #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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Macros omnipresence: Units 45
  • 92. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 92/184 • Adding derived dimensions is pretty easy in all the libraries • Adding base dimensions is hard or nearly impossible C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Extensibility 46
  • 93. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 93/184 • 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) C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Extensibility BOOST.UNITS 46
  • 94. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 94/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Extensibility UNITS 47
  • 95. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 95/184 C++ CoreHard Spring 2019 | Implementing a 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 48
  • 96. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 96/184 • The best possible user experience – compiler errors – debugging C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Requirements 49
  • 97. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 97/184 • The best possible user experience – compiler errors – debugging • Safety and performance – strong types – template metaprogramming – constexpr all the things C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Requirements 49
  • 98. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 98/184 • The best possible user experience – compiler errors – debugging • Safety and performance – strong types – template metaprogramming – constexpr all the things • No macros in the user interface • No external dependencies • Easy extensibility C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Requirements 49
  • 99. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 99/184 • The best possible user experience – compiler errors – debugging • Safety and performance – strong types – template metaprogramming – constexpr all the things • No macros in the user interface • No external dependencies • Easy extensibility • Possibility to be standardized as a freestanding part of the C++ Standard Library C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Requirements 49
  • 100. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 100/184 • units::dimension - a type-list-like type that stores an ordered list of exponents of one or more base dimensions template<typename... Exponents> struct dimension; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions 50
  • 101. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 101/184 • units::dimension - a type-list-like type that stores an ordered list of exponents of one or more base dimensions template<typename... Exponents> struct dimension; • units::exp - a base dimension and its exponent in a derived dimension template<typename BaseDimension, int Value> struct exp { using dimension = BaseDimension; static constexpr int value = Value; }; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions 50
  • 102. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 102/184 • BaseDimension is a unique sortable compile-time value C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions 51
  • 103. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 103/184 • BaseDimension is a unique sortable compile-time value template<int UniqueValue> using dim_id = std::integral_constant<int, UniqueValue>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions 51
  • 104. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 104/184 • 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> {}; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions EXAMPLE 51
  • 105. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 105/184 • 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> {}; C++ CoreHard Spring 2019 | Implementing a 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 51
  • 106. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 106/184 • Allow non-union class types to appear in non-type template parameters • Require that types used as such, have strong structural equality – a type T is having strong structural equality if each subobject recursively has defaulted == and none of the subobjects are floating point types C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ P0732 P1185 Class Types in Non-Type Template Parameters 52
  • 107. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 107/184 • Allow non-union class types to appear in non-type template parameters • Require that types used as such, have strong structural equality – a type T is having strong structural equality if each subobject recursively has defaulted == and none of the subobjects are floating point types template<fixed_string Id> class entity { /* ... */ }; entity<"hello"> e; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ P0732 P1185 Class Types in Non-Type Template Parameters 52
  • 108. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 108/184 • 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; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++20 Exponent and Base Dimension 53
  • 109. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 109/184 • 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"); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++20 Exponent and Base Dimension EXAMPLE 53
  • 110. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 110/184 • 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"); C++ CoreHard Spring 2019 | Implementing a 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 53
  • 111. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 111/184 • We can express velocity in the following way dimension<exp<base_dim_length, 1>, exp<base_dim_time, -1>> – improves user experience – as short as possible template instantiations – easy to understand by every engineer C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions 54
  • 112. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 112/184 • We can express velocity in the following way dimension<exp<base_dim_length, 1>, exp<base_dim_time, -1>> – improves user experience – as short as possible template instantiations – easy to understand by every engineer • The same type expected for both operations constexpr auto v1 = 1_m / 1_s; constexpr auto v2 = 2 / 2_s * 1_m; static_assert(std::is_same<decltype(v1), decltype(v2)>); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions PROBLEM 54
  • 113. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 113/184 template<typename... Exponents> struct make_dimension { using type = /* unspecified */; }; template<typename... Exponents> using make_dimension_t = make_dimension<Exponents...>::type; • Provides unique ordering for contained base dimensions • Aggregates two arguments of the same base dimension but di erent exponents • Eliminates two arguments of the same base dimension and with opposite equal exponents C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions: make_dimension factory helper 55
  • 114. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 114/184 template<typename... Exponents> struct make_dimension { using type = /* unspecified */; }; template<typename... Exponents> using make_dimension_t = make_dimension<Exponents...>::type; • Provides unique ordering for contained base dimensions • Aggregates two arguments of the same base dimension but di erent exponents • Eliminates two arguments of the same base dimension and with opposite equal exponents • To form a velocity make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Dimensions: make_dimension factory helper EXAMPLE 55
  • 115. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 115/184 • unit - the unit of a specific physical dimension template<typename Dimension, typename Ratio = std::ratio<1>> struct unit { using dimension = Dimension; using ratio = Ratio; }; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units 56
  • 116. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 116/184 • unit - the unit of a specific physical dimension template<typename Dimension, typename Ratio = std::ratio<1>> struct unit { using dimension = Dimension; using ratio = Ratio; }; To express meter unit<dimension_length> C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Units EXAMPLE 56
  • 117. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 117/184 • quantity - the amount of a specific dimension expressed in a specific unit of that dimension template<typename Dimension, typename Unit, typename Rep> class quantity; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Quantities 57
  • 118. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 118/184 • quantity - the amount of a specific dimension expressed in a specific unit of that dimension template<typename Dimension, typename Unit, typename Rep> class quantity; • Interface similar to std::chrono::duration + additional member functions – multiplication of 2 quantities with di erent dimensions 1_kmph * 1_h == 1_km – division of 2 quantities of di erent dimensions 1_km / 1_h == 1_kmph – division of a scalar with a quantity 1 / 1_s == 1_Hz C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Quantities 57
  • 119. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 119/184 • quantity - the amount of a specific dimension expressed in a specific unit of that dimension template<typename Dimension, typename Unit, typename Rep> class quantity; template<typename Unit = meter_per_second, typename Rep = double> using velocity = quantity<dimension_velocity, Unit, Rep>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Quantities EXAMPLE 58
  • 120. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 120/184 What is the quantity? An absolute or a relative value? C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Important design question 59
  • 121. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 121/184 What is the quantity? An absolute or a relative value? • For most dimensions only relative values have sense – Where is absolute 123 meters? – If I am sitting in a moving train is my velocity == 0? – Is my velocity == 0 when the train stops? C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Important design question 59
  • 122. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 122/184 What is the quantity? An absolute or a relative value? • For most dimensions only relative values have sense – Where is absolute 123 meters? – If I am sitting in a moving train is my velocity == 0? – Is my velocity == 0 when the train stops? • For some dimensions absolute values are really needed – temperature – time C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Important design question 59
  • 123. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 123/184 1 Generic programming 2 Compile-time errors 3 Debugging C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Struggling with the user experience 60
  • 124. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 124/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Do you remember that? BOOST.UNITS UNITS 61
  • 125. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 125/184 #include <boost/units/is_quantity_of_dimension.hpp> template<typename Quantity, typename Dimension> concept QuantityOf = bu::is_quantity_of_dimension<Quantity, Dimension>::value; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++ Concepts to the rescue BOOST.UNITS 62
  • 126. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 126/184 #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>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++ Concepts to the rescue BOOST.UNITS 62
  • 127. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 127/184 #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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++ Concepts to the rescue BOOST.UNITS 62
  • 128. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 128/184 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; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++ Concepts to the rescue UNITS 63
  • 129. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 129/184 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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++ Concepts to the rescue UNITS 63
  • 130. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 130/184 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; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++ Concepts to the rescue UNITS Concepts can also be used in places where regular template argument deduction does not work (i.e. return types, class template parameters, etc). 63
  • 131. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 131/184 All template types are heavily embraced with concepts C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ I lied a bit ;-) 64
  • 132. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 132/184 • TypeList • Scalar • Ratio • Exponent • Dimension • Unit • Quantity All template types are heavily embraced with concepts C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ I lied a bit ;-) UNITS ENGINE CONCEPTS 64
  • 133. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 133/184 • TypeList • Scalar • Ratio • Exponent • Dimension • Unit • Quantity • Length • Time • Frequency • Velocity • ... template<typename T> concept Velocity = Quantity<T> && std::Same<typename T::dimension, dimension_velocity>; All template types are heavily embraced with concepts C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ I lied a bit ;-) UNITS ENGINE CONCEPTS PREDEFINED QUANTITIES CONCEPTS 64
  • 134. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 134/184 • 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>>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Type aliases are great (but not for users) 65
  • 135. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 135/184 • 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Type aliases are great (but not for users) 65
  • 136. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 136/184 • 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>] C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Type aliases are great (but not for users) 65
  • 137. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 137/184 • 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>] C++ CoreHard Spring 2019 | Implementing a 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 :-( 65
  • 138. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 138/184 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Inheritance to the rescue 66
  • 139. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 139/184 Velocity auto v = 10_m / 2_s; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting problem 67
  • 140. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 140/184 Velocity auto v = 10_m / 2_s; template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2> constexpr Quantity operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting problem 67
  • 141. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 141/184 Velocity auto v = 10_m / 2_s; template<Dimension D1, Unit U1, Scalar Rep1, Dimension D2, Unit U2, Scalar Rep2> constexpr Quantity operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs); C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting problem How to form dimension_velocity child class from division of dimension_length by dimension_time? 67
  • 142. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 142/184 template<typename T> struct type_identity { using type = T; }; template<typename T> using type_identity_t = type_identity<T>::type; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ P0887 The identity metafunction 68
  • 143. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 143/184 template<typename BaseType> struct upcast_base { using base_type = BaseType; }; template<Exponent... Es> struct dimension : upcast_base<dimension<Es...>> {}; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting facility BASE CLASS 69
  • 144. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 144/184 template<typename BaseType> struct upcast_base { using base_type = BaseType; }; template<Exponent... Es> struct dimension : upcast_base<dimension<Es...>> {}; template<typename T> concept Upcastable = requires { typename T::base_type; } && std::DerivedFrom<T, upcast_base<typename T::base_type>>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting facility BASE CLASS UPCASTABLE 69
  • 145. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 145/184 template<Upcastable T> using upcast_from = T::base_type; template<Upcastable T> using upcast_to = std::type_identity<T>; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting facility HELPER ALIASES 70
  • 146. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 146/184 template<Upcastable T> using upcast_from = T::base_type; template<Upcastable T> using upcast_to = std::type_identity<T>; template<Upcastable T> struct upcasting_traits : upcast_to<T> {}; template<Upcastable T> using upcasting_traits_t = upcasting_traits<T>::type; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting facility HELPER ALIASES UPCASTING TRAITS 70
  • 147. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 147/184 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>> {}; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting dimension 71
  • 148. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 148/184 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>> {}; template<> struct upcasting_traits<upcast_from<dimension_velocity>> : upcast_to<dimension_velocity> {}; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting dimension 71
  • 149. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 149/184 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>> {}; template<> struct upcasting_traits<upcast_from<dimension_velocity>> : upcast_to<dimension_velocity> {}; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting dimension Help needed: How to automate the last line? 71
  • 150. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 150/184 [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>] C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting facility BEFORE 72
  • 151. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 151/184 [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> C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Upcasting facility BEFORE AFTER 72
  • 152. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 152/184 template<Dimension D, Unit U, Scalar Rep> requires std::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> [[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != quantity<D, U2, Rep2>(0)); // ... } }; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Contracts 73
  • 153. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 153/184 template<Dimension D, Unit U, Scalar Rep> requires std::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> [[nodiscard]] constexpr Scalar 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 C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Contracts 73
  • 154. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 154/184 template<Dimension D, Unit U, Scalar Rep> requires std::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> [[nodiscard]] constexpr Scalar 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)); // ... } }; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Contracts 74
  • 155. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 155/184 template<Dimension D, Unit U, Scalar Rep> requires std::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> [[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0)); // ... } }; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Contracts 75
  • 156. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 156/184 template<Dimension D, Unit U, Scalar Rep> requires std::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> [[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) { Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0)); // ... } }; C++ CoreHard Spring 2019 | Implementing a 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 75
  • 157. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 157/184 template<Dimension D, Unit U, Scalar Rep> requires std::Same<D, typename U::dimension> class quantity { public: template<Dimension D, Unit U1, Scalar Rep1, Unit U2, Scalar Rep2> [[nodiscard]] constexpr Scalar operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs) [[expects: rhs != quantity<D, U2, Rep2>(0)]] { // ... } }; C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ C++20 Contracts 76
  • 158. 25.05.2019 Implementing a Physical Units Library for C++ file:///C:/repos/cpptrainings_refactor/build/out/implementing_units/implementing_units.html#1 158/184 constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d / t; } C++ CoreHard Spring 2019 | Implementing a Physical Units Library for C++ Toy example 77