Is it possible to print Roman numbers instead of int?

I have a code that prints some small numbers (actually years), and the request should contain numbers printed as Roman numbers instead of using regular Hindu-Arabic numbers :

int main() {
    // do something to make all integers appear in Roman numerals
    std::cout << "In the year " << 2013 << " the following output was generated:\n";
    // ...
}

What can be done to format intas roman numerals?

+4
source share
1 answer

There are two parts to the question:

  • The boring part of the question is how to convert a intRoman string to a sequence of characters.
  • int .

, , -, . , IOStreams, :

template <typename To>
To make_roman(int 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;
}

"" . , , . , , 15 (3888).

- std::cout , int . std::ostream ( , ) bool void const*, std::num_put<cT> std::locale put() ,

std::use_facet<std::num_put<cT>>(s.getloc())
    .put(std::ostreambuf_iterator<char>(s), s, s.fill(), value);

std::num_put<char> - do_put() , a long , :

class num_put
    : public std::num_put<char>
{
    iter_type do_put(iter_type to, std::ios_base& fmt, char fill, long 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;
    }
};

, :

  • v buffer.
  • ( width() reset 0).
  • , , , ( ), .

std::locale std::num_put<char> std::locale std::cout:

std::cout.imbue(std::locale(std::cout.getloc(), new num_put));
std::cout << "year " << 2013 << '\n';

- , . do_put() (.. long, long long, unsigned long unsigned long long).

+13

All Articles