Skip to content

Instantly share code, notes, and snippets.

@nicola-gigante
Created June 3, 2015 15:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicola-gigante/f0677f6f4f97b9f08c5e to your computer and use it in GitHub Desktop.
Save nicola-gigante/f0677f6f4f97b9f08c5e to your computer and use it in GitHub Desktop.
Minimalist metaprogramming example in the spirit of Boost.Units
//
// 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;
}
//
// 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