#include <iostream>

/* SI unit exponents */
struct Unit {
    int M;
    int KG;
    int S;
};

constexpr Unit operator*(Unit a, Unit b) {
    return Unit{a.M + b.M, a.KG + b.KG, a.S + b.S};
}
constexpr Unit operator/(Unit a, Unit b) {
    return Unit{a.M - b.M, a.KG - b.KG, a.S - b.S};
}

/* quantity in SI unit */
template <Unit U>
class Quantity {
  public:
    double magnitude;
    explicit Quantity(double magnitude): magnitude{magnitude} {}
};

/* short names for quantities */
using Length = Quantity<Unit{1, 0, 0}>;         /* hossz, m */
using Area = Quantity<Unit{2, 0, 0}>;           /* terület, m^2 */
using Mass = Quantity<Unit{0, 1, 0}>;           /* tömeg, kg */
using Time = Quantity<Unit{0, 0, 1}>;           /* idő, s */
using Speed = Quantity<Unit{1, 0, -1}>;         /* sebesség, m/s */
using Acceleration = Quantity<Unit{1, 0, -2}>;  /* gyorsulás, m/s^2 */
using Force = Quantity<Unit{1, 1, -2}>;         /* erő, N=m*kg/s^2 */
using Energy = Quantity<Unit{2, 1, -2}>;        /* energia, J=m^2*kg/s^2 */
using Power = Quantity<Unit{2, 1, -3}>;         /* teljesítmény, Watt = Joule/s = m^2*kg/s^3 */


/* operators for quantities */
template <Unit U>
Quantity<U> operator+(Quantity<U> a, Quantity<U> b) {
    return Quantity<U>{a.magnitude + b.magnitude};
}
 
template <Unit U>
Quantity<U> operator-(Quantity<U> a, Quantity<U> b) {
    return Quantity<U>{a.magnitude - b.magnitude};
}

template <Unit U1, Unit U2>
Quantity<U1*U2> operator*(Quantity<U1> a, Quantity<U2> b) {
    return Quantity<U1*U2>{a.magnitude * b.magnitude};
}
 
template <Unit U1, Unit U2>
Quantity<U1/U2> operator/(Quantity<U1> a, Quantity<U2> b) {
    return Quantity<U1/U2>{a.magnitude / b.magnitude};
}


/* generic stream inserter operator for quantities */
template <Unit U>
std::ostream & operator<<(std::ostream & os, Quantity<U> m) {
    os << m.magnitude << ' ';
    bool elso = true;
    if (U.M != 0) {
        elso = false;
        os << "m^" << U.M;
    }
    if (U.KG != 0) {
        if (!elso) os << '*';
        elso = false;
        os << "kg^" << U.KG;
    }
    if (U.S != 0) {
        if (!elso) os << '*';
        elso = false;
        os << "s^" << U.S;
    }
    return os;
}


/* specialized stream inserter operator for force */
template <>
std::ostream & operator<<(std::ostream & os, Force m) {
    os << m.magnitude << " N";
    return os;
}


int main() {
    std::cout << "Ferrari ===" << std::endl;
    Length l{100 * 1000};   /* 100 km */
    Time hour{3600};        /* óra = 3600 s */
    Time t{4};              /* gyorsulás: 4 s alatt */
    Mass m{1450};           /* az autó tömege: 1450 kg */
    
    Speed v = l/hour;
    std::cout << "100 km/h = " << v << std::endl;
    
    Acceleration a = v/t;
    Force f = m*a;          /* Newton */
    std::cout << "F = " << f << std::endl;
}
