Can I print an object of the C++ class using fmt library?
fmt::print("The object is {}.", obj);
Yes, it is possible. As suggested in the comments, fmt provides support for custom types directly: Formatting user defined types.
I normally prefer an alternative approach using std::ostream. When you implement operator<< for std::ostream and your custom type, fmt will be able to format your custom type provided that you include <fmt/ostream.h> as well. For example:
#include <fmt/format.h>
#include <fmt/ostream.h>
struct A {};
std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << "A!";
}
int main()
{
fmt::print("{}\n", A{});
return 0;
}
Keep in mind that this approach will likely be much slower than the initial suggestion of going through fmt directly.
Update: To support the claim that using <fmt/ostream.h> is slower than going through fmt directly, you can use the following benchmark (using Google Benchmark):
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <benchmark/benchmark.h>
struct A {};
std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << "A!";
}
struct B {};
template<>
struct fmt::formatter<B>
{
template<typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template<typename FormatContext>
auto format(const B& b, FormatContext& ctx)
{
return format_to(ctx.out(), "B!");
}
};
static void BM_fmt_ostream(benchmark::State& state)
{
for (auto _ : state)
{
benchmark::DoNotOptimize(fmt::format("{}", A{}));
}
}
static void BM_fmt_direct(benchmark::State& state)
{
for (auto _ : state)
{
benchmark::DoNotOptimize(fmt::format("{}", B{}));
}
}
BENCHMARK(BM_fmt_direct);
BENCHMARK(BM_fmt_ostream);
int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
return 0;
}
Output on my machine:
2019-10-29 12:15:57
Running ./fmt
Run on (4 X 3200 MHz CPU s)
CPU Caches:
L1 Data 32K (x2)
L1 Instruction 32K (x2)
L2 Unified 256K (x2)
L3 Unified 4096K (x1)
Load Average: 0.53, 0.50, 0.60
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------
BM_fmt_direct 42 ns 42 ns 16756571
BM_fmt_ostream 213 ns 213 ns 3327194
Yes. You can do this by providing a formatter specialization for your type as described in Formatting User-defined Types:
#include <fmt/format.h>
struct point { double x, y; };
template <> struct fmt::formatter<point> {
constexpr auto parse(format_parse_context &ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const point &p, FormatContext &ctx) const {
return format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y);
}
};
You can also reuse existing formatters via composition or inheritance in which case you might only need to implement the format function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With