Created
June 3, 2015 15:53
-
-
Save nicola-gigante/f0677f6f4f97b9f08c5e to your computer and use it in GitHub Desktop.
Minimalist metaprogramming example in the spirit of Boost.Units
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Boost.Units-like demo | |
// C++ User Group Udine | |
// | |
#include "units.h" | |
int main() | |
{ | |
quantity<mass> m = 42 * kilogram; | |
quantity<mass> m2 = 2 * kilogram; | |
quantity<acceleration> a = 2 * (meter/(second*second)); | |
quantity<force> f = m * a; | |
// Uncomment for a compile time error | |
// quantity<force> f = m / a; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// units.h | |
// | |
// Boost.Units-like demo | |
// C++ User Group Udine | |
// | |
#ifndef UNITS_H__ | |
#define UNITS_H__ | |
// Compile-time tuple of ints. | |
// Each component is the exponent of the corresponding base unit | |
template< | |
int L, // length | |
int M, // mass | |
int T, // time | |
int I, // current | |
int H, // temperature | |
int N, // amount of substance | |
int J> // luminous intensity | |
struct unit; | |
// | |
// Quantity: a numeric value + a measure unit | |
// | |
template<typename Unit> | |
class quantity | |
{ | |
double _value{}; | |
public: | |
using unit = Unit; | |
// Default, copy, move constructurs | |
constexpr quantity() = default; | |
constexpr quantity(quantity const&) = default; | |
constexpr quantity(quantity &&) = default; | |
// Copy, move assignment operators | |
quantity &operator=(quantity const&) = default; | |
quantity &operator=(quantity &&) = default; | |
// Explicit conversion from T | |
explicit constexpr quantity(double v) : _value(v) { } | |
constexpr double value() const { return _value; } | |
}; | |
// | |
// Base physical quantities typedefs | |
// | |
using adimensional = unit<0, 0, 0, 0, 0, 0, 0>; | |
using length = unit<1, 0, 0, 0, 0, 0, 0>; | |
using mass = unit<0, 1, 0, 0, 0, 0, 0>; | |
using time_ = unit<0, 0, 1, 0, 0, 0, 0>; | |
using current = unit<0, 0, 0, 1, 0, 0, 0>; | |
using temperature = unit<0, 0, 0, 0, 1, 0, 0>; | |
using amount = unit<0, 0, 0, 0, 0, 1, 0>; | |
using luminosity = unit<0, 0, 0, 0, 0, 0, 1>; | |
// Metafunctions to compute the result of arithmetical operations on units | |
// | |
// Product | |
// | |
template<typename U1, typename U2> | |
struct product_t; | |
template< | |
int L1, int M1, int T1, int I1, int H1, int N1, int J1, | |
int L2, int M2, int T2, int I2, int H2, int N2, int J2 | |
> | |
struct product_t<unit<L1,M1,T1,I1,H1,N1,J1>, unit<L2,M2,T2,I2,H2,N2,J2>> { | |
using type = | |
unit<L1 + L2, M1 + M2, T1 + T2, I1 + I2, H1 + H2, N1 + N2, J1 + J2>; | |
}; | |
template<typename U1, typename U2> | |
using product = typename product_t<U1, U2>::type; | |
// | |
// Reciprocal | |
// | |
template<typename U> | |
struct reciprocal_t; | |
template<int L, int M, int T, int I, int H, int N, int J> | |
struct reciprocal_t<unit<L, M, T, I, H, N, J>> | |
{ | |
using type = unit<-L, -M, -T, -I, -H, -N, -J>; | |
}; | |
template<typename U> | |
using reciprocal = typename reciprocal_t<U>::type; | |
// | |
// Division | |
// | |
template<typename U1, typename U2> | |
using division = product<U1, reciprocal<U2>>; | |
// | |
// Operators | |
// | |
// Sum | |
template<typename U> | |
auto operator+(quantity<U> q1, quantity<U> q2) | |
{ | |
return quantity<U>{q1.value() + q2.value()}; | |
} | |
// Product | |
template<typename U1, typename U2> | |
auto operator*(quantity<U1> q1, quantity<U2> q2) | |
{ | |
return quantity<product<U1, U2>>(q1.value() * q2.value()); | |
} | |
// Product with scalar | |
template<typename U> | |
auto operator*(quantity<U> q, double scalar) | |
{ | |
return quantity<U>(q.value() * scalar); | |
} | |
template<typename U> | |
auto operator*(double scalar, quantity<U> q) | |
{ | |
return quantity<U>(scalar * q.value()); | |
} | |
// Product with adimensional quantity | |
template<typename U> | |
auto operator*(quantity<U> q, quantity<adimensional> scalar) | |
{ | |
return quantity<U>(q.value() * scalar.value()); | |
} | |
template<typename U> | |
auto operator*(quantity<adimensional> scalar, quantity<U> q) | |
{ | |
return quantity<U>(scalar.value() * q.value()); | |
} | |
// Division by scalar | |
template<typename U> | |
auto operator/(quantity<U> q, double scalar) | |
{ | |
return quantity<U>(q.value() / scalar); | |
} | |
// Reciprocal | |
template<typename U> | |
auto operator/(double scalar, quantity<U> q) | |
{ | |
return quantity<reciprocal<U>>(scalar / q.value()); | |
} | |
// Division | |
template<typename U1, typename U2> | |
auto operator/(quantity<U1> q1, quantity<U2> q2) | |
{ | |
return quantity<division<U1, U2>>(q1.value() / q2.value()); | |
} | |
// | |
// Base units objects | |
// | |
constexpr const quantity<length> meter {1.0}; | |
constexpr const quantity<mass> kilogram {1.0}; | |
constexpr const quantity<time_> second {1.0}; | |
constexpr const quantity<current> ampere {1.0}; | |
constexpr const quantity<temperature> kelvin {1.0}; | |
constexpr const quantity<amount> mole {1.0}; | |
constexpr const quantity<luminosity> candela {1.0}; | |
// | |
// Some derived quantities | |
// | |
using speed = division<length, time_>; | |
using acceleration = division<speed, time_>; | |
using force = product<mass, acceleration>; | |
// Derived units | |
constexpr const quantity<force> newton{1.0}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment