toml11 icon indicating copy to clipboard operation
toml11 copied to clipboard

How to print `toml::value` returned from `toml::parse()` with `fmt::print()` properly?

Open hwhsu1231 opened this issue 2 years ago • 1 comments

Problem Description

It is related to the issue: https://github.com/fmtlib/fmt/issues/2894

According to vitaut's comment:

{fmt} doesn't provide formatters for toml11 types. You should check which formatter is being used and address your question to its author.

What should I do?

hwhsu1231 avatar May 15 '22 07:05 hwhsu1231

First of all, since I'm not an author of {fmt}, I don't know much about the implementation detail of the library. But I took a glance at the code and found that the example code shown in your link seems to use fallback_formatter that internally calls operator<<(ostream&, T). If I'm not mistaken, it does not set std::setw. Since operator<<(ostream&, toml::value) reads width setting in ostream, if width is not set, it does nothing.

There are several options:

  1. implementing {fmt} formatter that parses width specifier and pass it to setw or toml::format. I think this is the most appropriate (but could be painful) way.
  2. wrapping a toml::value by a struct that has width and define operator<< to use width internally. This is easy but makes code messy.

{fmt} documentation explains how to write a formatter: https://fmt.dev/latest/api.html#format-api.

The second option will look like:

#define FMT_DEPRECATED_OSTREAM
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <toml.hpp>
#include <iostream>

struct width_setter
{
    width_setter(std::size_t w, const toml::value& v): width_(w), data_(v) {}
    std::size_t width_;
    toml::value const& data_;
};

template <typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const width_setter& w)
{
    os << std::setw(w.width_) << w.data_;
    return os;
}

int main(int argc, char **argv)
{
    if(argc != 2)
    {
        fmt::print("usage: ./toml11fmt example.toml\n");
        return 1;
    }
    const auto data = toml::parse(std::string(argv[1]));

    std::cout << std::setw(80) << data << std::endl;
    fmt::print(std::cout, "{}", width_setter(80, data));
    return 0;
}

ToruNiina avatar May 15 '22 15:05 ToruNiina