fiet/SISystem

Wouldn't it be nice if this would be possible?

int main()
{
  Second a(2);
  Second b(4);
  Second c = a + b;
  c += b;
  Meter d(3);

  std::cout << d.toString() << "\n";
  std::cout << c.toString() << "\n";

  Velocity v = d/a;
  std::cout << v.toString() << "\n";
}

Where the output would be:

3  m^1 
10  s^1 
1.5  s^-1 m^1 

Below you can find the implementation of a compile time type safe SI system in C++ using templates :) The only thing I'm not happy with: the error messages are somewhat unreadable ;-)

#include <sstream>
#include <iostream>

template <
  int SECOND = 0,
  int METER = 0,
  int KILOGRAM = 0,
  int AMPERE = 0,
  int KELVIN = 0,
  int MOL = 0,
  int CANDELA = 0>
class Unit
{
  template<int, int, int, int, int, int, int> friend class Unit;
public:
  static const int s = SECOND;
  static const int m = METER;
  static const int kg = KILOGRAM;
  static const int A = AMPERE;
  static const int K = KELVIN;
  static const int mol = MOL;
  static const int cd = CANDELA;

  Unit() :
    value(0)
  {}

  explicit
  Unit(double v) :
    value(v)
  {}

  ~Unit()
  {}

  // default copy and assignment c'tor are ok

  // overload operators

  // "+" and "-" are easy
  Unit
  operator +(const Unit& other)
  {
    return Unit(value + other.value);
  }

  Unit
  operator -(const Unit& other)
  {
    return Unit(value - other.value);
  }

  void
  operator +=(const Unit& other)
  {
    value += other.value;
  }

  void
  operator -=(const Unit& other)
  {
    value -= other.value;
  }
  
  // "*" and "/" are more interesting ... but easy as well
  template <typename T>
  Unit<
    s+T::s,
    m+T::m,
    kg+T::kg,
    A+T::A,
    K+T::K,
    mol+T::mol,
    cd+T::cd>
  operator *(const T& other)
  {
    return Unit<
      s+T::s,
      m+T::m,
      kg+T::kg,
      A+T::A,
      K+T::K,
      mol+T::mol,
      cd+T::cd>(value*other.value);
  }

  template <typename T>
  Unit<
    s-T::s,
    m-T::m,
    kg-T::kg,
    A-T::A,
    K-T::K,
    mol-T::mol,
    cd-T::cd>
  operator /(const T& other)
  {
    return Unit<
      s-T::s,
      m-T::m,
      kg-T::kg,
      A-T::A,
      K-T::K,
      mol-T::mol,
      cd-T::cd>(value/other.value);
  }
  
  // *= and /= are not defined!

  double
  toDouble() const
  {
    return value;
  }

  std::string
  toString() const
  {
    std::stringstream ss;
    ss << value << "  ";
    if (0 != s)
      {
        ss << "s^" << s << " ";
      }
    if (0 != m)
      {
        ss << "m^" << m << " ";
      }
    if (0 != kg)
      {
        ss << "kg^" << kg << " ";
      }
    if (0 != A)
      {
        ss << "A^" << A << " ";
      }
    if (0 != K)
      {
        ss << "K^" << K << " ";
      }
    if (0 != mol)
      {
        ss << "mol^" << mol << " ";
      }
    if (0 != cd)
      {
        ss << "cd^" << cd << " ";
      }
    return ss.str();
  }
  
private:
  // keeps the value
  double value;
};

typedef Unit<1> Second;
typedef Unit<0, 1> Meter;
typedef Unit<-1> Hz;
typedef Unit<-1, 1> Velocity;
typedef Unit<-3, 2, 1> Watt;
// I think you get the thingy ...

int main()
{
  Second a(2);
  Second b(4);
  Second c = a + b;
  c += b;
  Meter d(3);

  std::cout << d.toString() << "\n";
  std::cout << c.toString() << "\n";

  Velocity v = d/a;
  std::cout << v.toString() << "\n";
}