Home > Enterprise >  format boost multiprecision cpp_int with fmt
format boost multiprecision cpp_int with fmt

Time:12-10

I'm trying to format a boost multiprecision cpp_int using fmt library.

Here's the code I tried

using boost::multiprecision::cpp_int;

int main() {
    cpp_int v("0x8FFFFFFFFFFFFFFFF");
    std::string buffer;   
    fmt::format_to(std::back_inserter(buffer),"{}", v);
    std::cout << buffer;
}

https://godbolt.org/z/M4zKc5hr6 using boost 1.73, fmt 9.1, gcc 7.3

I'm getting compilation error:

error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter specialization

I stumbled upon this issue https://github.com/fmtlib/fmt/issues/918 that seems to be resolved, so I was expecting fmt to be able to format boost multiprecision numbers. Do I still need to write a formatter specialization?

CodePudding user response:

You need to provide a formatter. E.g. you can opt-in to the ostream formatter:

template <> struct fmt::formatter<cpp_int> : fmt::ostream_formatter {};

Live demo: Live On Coliru

#include <boost/multiprecision/cpp_int.hpp>
#include <fmt/format.h>
#include <fmt/ostream.h>
using boost::multiprecision::cpp_int;

template <> struct fmt::formatter<cpp_int> : fmt::ostream_formatter {};

int main() {
    cpp_int v("0x8FFFFFFFFFFFFFFFF");

    std::string buffer;
    fmt::format_to(std::back_inserter(buffer), "Hello world: {}", v);

    fmt::print("Print directly: {} (buffer: {})", v, buffer);
}

Outputs:

Print directly: 166020696663385964543 (buffer: Hello world: 166020696663385964543)

BONUS: Hex, showbase, lower/uppercase

Demonstrating a simple custom formatter that invokes i.str(...) with the required formatting parameters:

Live On Coliru

#include <boost/multiprecision/cpp_int.hpp>
#include <fmt/format.h>
using boost::multiprecision::cpp_int;

template <> struct fmt::formatter<cpp_int> {
    uint8_t showbase_ : 1 = 0, hex_ : 1 = 0, upper_ : 1 = 0;

    auto constexpr parse(auto& ctx) {
        auto e = std::find(ctx.begin(), ctx.end(), '}');
        if (std::string_view f{ctx.begin(), e}; f == "#x")
            showbase_ = hex_ = true;
        else if (f == "#X")
            showbase_ = hex_ = upper_ = true;
        else {
            hex_   = (f == "x") || (f == "X");
            upper_ = (f == "X");
        }
        return e;
    }

    auto format(cpp_int const& i, auto& ctx) {
        auto f = hex_ ? std::ios::hex : std::ios::dec;
        if (showbase_) f |= std::ios::showbase;
        if (upper_)    f |= std::ios::uppercase;
        auto s = i.str(0, f);
        return std::copy(s.begin(), s.end(), ctx.out());
    }
};

int main() {{
    cpp_int v("0x8FFFFFFFFFFFFFFFF");

    fmt::print("{{}}:    {}\n", v);
    fmt::print("{{:}}:   {:}\n", v);
    fmt::print("{{:x}}:  {:x}\n", v);
    fmt::print("{{:#x}}: {:#x}\n", v);
    fmt::print("{{:X}}:  {:X}\n", v);
    fmt::print("{{:#X}}: {:#X}\n", v);
}}

Prints

{}:    166020696663385964543
{:}:   166020696663385964543
{:x}:  8ffffffffffffffff
{:#x}: 0x8ffffffffffffffff
{:X}:  8FFFFFFFFFFFFFFFF
{:#X}: 0X8FFFFFFFFFFFFFFFF
  • Related