c++ – API for value boxing and unboxing

This is a class representing an exponent. Its main purpose is to deal with logarithmic quantities.

template<std::floating_point Representation>
class Exponent
{
    public:
        using representation = Representation;

        struct Literal{};

        constexpr explicit Exponent(representation val, Literal):m_val{val}
        {}

        constexpr explicit Exponent(representation val):m_val{std::log2(val)}
        {}

        constexpr representation value() const
        {
            return m_val;
        }

        constexpr operator representation() const
        {
            return std::exp2(m_val);
        }

        constexpr Exponent& operator+=(Exponent other)
        {
            m_val += other.m_val;
            return *this;
        }

        constexpr Exponent& operator-=(Exponent other)
        {
            m_val -= other.m_val;
            return *this;
        }

        constexpr Exponent& operator/=(Exponent other)
        {
            m_val /= other.m_val;
            return *this;
        }

        constexpr Exponent& operator*=(Exponent other)
        {
            m_val *= other.m_val;
            return *this;
        }

        constexpr auto operator<=>(Exponent const&) const = default;

    private:
        representation m_val;
};

template<std::floating_point T>
constexpr Exponent<T> operator+(Exponent<T> a, Exponent<T> b)
{
    return a+=b;
}

//...

What I am not sure about is how to properly disambiguate between data converting casts (taking logarithm vs exponent) operations and pure value casts (simple assign).

Another question is if the API should emulate real values. With the above API:

constexpr double multiply(double a, double b)
{return Exponent{a} + Exponent{b};}

static_assert(multiply(2.0, 3.0) == 6.0);

However, if you define operator* on exponents to behave as addition, you would instead simply write:

constexpr double multiply(Exponent a, Exponent b)
{return a*b;}

static_assert(multiply(2.0, 3.0) == 6.0);