#include <iostream>

namespace Units {

    /* 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;
        constexpr explicit Quantity(double magnitude): magnitude{magnitude} {}

        bool operator==(Quantity const& other) const {
           return magnitude == other.magnitude;
        }
        std::partial_ordering operator<=>(Quantity const& other) const {
            return magnitude <=> other.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 Torque = Quantity<Unit{2, 1, -2}>;         /* forgatónyomaték, Nm=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;
    }


    /* user-defined literals for SI quantities */
    namespace Literals {

        constexpr Length operator "" _m (long double magnitude) {
            return Length(magnitude);
        }

        constexpr Length operator "" _km (long double magnitude) {
            return Length(magnitude * 1000.0);
        }

        constexpr Time operator "" _s (long double magnitude) {
            return Time(magnitude);
        }

        constexpr Time operator "" _h (long double magnitude) {
            return Time(magnitude * 3600);
        }

        constexpr Mass operator "" _kg (long double magnitude) {
            return Mass(magnitude);
        }

        constexpr Force operator "" _N (long double magnitude) {
            return Force(magnitude);
        }
    } /* namespace Literals */

} /* namespace Units */


int main() {
    using namespace Units::Literals;

    std::cout << "Ferrari ===" << std::endl;
    Units::Speed v = 100.0_km / 1.0_h;
    std::cout << "100 km/h = " << v << std::endl;

    Units::Acceleration a = v / 4.0_s;
    Units::Force f = 1450.0_kg * a;          /* Newton */
    std::cout << "F = " << f << std::endl;
}

