#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <locale>
#include <stdexcept>
#include <string>

template <typename Value, typename To>
To make_roman(Value value, To to) {
    if (value < 1 || 3999 < value) {
        throw std::range_error("int out of range for a Roman numeral");
    }
    static std::string const digits[4][10] = {
        { "", "M", "MM", "MMM", "", "", "", "", "", "" },
        { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" },
        { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" },
        { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" },
    };
    for (int i(0), factor(1000); i != 4; ++i, factor /= 10) {
        std::string const& s(digits[i][(value / factor) % 10]);
        to = std::copy(s.begin(), s.end(), to);
    }
    return to;
}

    class num_put
        : public std::num_put<char>
    {
        template <typename Value>
        iter_type format(iter_type to, std::ios_base& fmt, char fill,
                         Value v) const {
            char buffer[16];
            char* end(make_roman(v, buffer));
    
            std::streamsize len(end - buffer);
            std::streamsize width(std::max(fmt.width(0), len));
            std::streamsize fc(width - (end - buffer));
            switch (fmt.flags() & std::ios_base::adjustfield) {
            default:
            case std::ios_base::left:
                to = std::copy(buffer, end, to);
                to = std::fill_n(to, fc, fill);
                break;
            case std::ios_base::right:
            case std::ios_base::internal:
                to = std::fill_n(to, fc, fill);
                to = std::copy(buffer, end, to);
            }
            return to;
        }
        iter_type do_put(iter_type to, std::ios_base& fmt, char fill,
                         long v) const {
            return this->format(to, fmt, fill, v);
        }
        iter_type do_put(iter_type to, std::ios_base& fmt, char fill,
                         long long v) const {
            return this->format(to, fmt, fill, v);
        }
        iter_type do_put(iter_type to, std::ios_base& fmt, char fill,
                         unsigned long v) const {
            return this->format(to, fmt, fill, v);
        }
        iter_type do_put(iter_type to, std::ios_base& fmt, char fill,
                         unsigned long long v) const {
            return this->format(to, fmt, fill, v);
        }
    };
 
int main()
{
    try {
        std::locale  rloc(std::locale(), new num_put);
        std::ostream lout(std::cout.rdbuf());
        std::ostream rout(std::cout.rdbuf());
        (lout << std::left).imbue(rloc);
        (rout << std::right).imbue(rloc);

        lout << "long=" << static_cast<long>(1234) << '\n'
             << "unsigned long=" << static_cast<unsigned long>(1234) << '\n'
             << "long long=" << static_cast<long long>(1234) << '\n'
             << "unsigned long long=" << static_cast<unsigned long long>(1234) << '\n'
            ;

        for (int i = 59; i < 4000; i += 59) {
            std::cout << std::setw(4) << i << '=';
            lout << '\'' << std::setw(12) << i << "' ";
            rout << '\'' << std::setw(12) << i << "'\n";
        }
    }
    catch (std::exception const& ex) {
        std::cout << "ERROR: " << ex.what() << '\n';
    }
}
