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:
#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