STL icon indicating copy to clipboard operation
STL copied to clipboard

`<format>`: Underlying formatters of `pair-or-tuple` formatter cannot access format args

Open JMazurkiewicz opened this issue 1 year ago • 3 comments

Underlying formatters of pair-or-tuple formatter should be able to call format_ctx.arg(I) and get correct format arg.

Example:

#include <print>
#include <thread>

template <size_t I> struct substitute_arg {};

template <size_t I> struct std::formatter<substitute_arg<I>> {
  template <class ParseContext> constexpr auto parse(ParseContext &ctx) {
    auto it = ctx.begin();
    if (it != ctx.end() && *it != '}') {
      throw format_error{"Expected empty spec"};
    }

    ctx.check_arg_id(I);
    return it;
  }

  template <class FormatContext>
  auto format(substitute_arg<I>, FormatContext &ctx) const {
    auto visitor = [&]<class T>(T val) -> FormatContext::iterator {
      if constexpr (same_as<T, monostate>) {
        return ranges::copy("monostate"sv, ctx.out()).out;
      } else if constexpr (same_as<T, typename basic_format_arg<
                                          FormatContext>::handle>) {
        format_parse_context parse_ctx{""};
        val.format(parse_ctx, ctx);
        return ctx.out();
      } else {
        return format_to(ctx.out(), "{}", val);
      }
    };

    return visit_format_arg(visitor, ctx.arg(I));
  }
};

int main() {
  std::println("{0:}", std::tuple{substitute_arg<1>{}, substitute_arg<2>{}},
               "thread::id", std::thread::id{});
}

Expected output (libc++: https://godbolt.org/z/1c4fdhzTb):

(thread::id, 0)

We've got:

(monostate, monostate)

JMazurkiewicz avatar May 03 '24 09:05 JMazurkiewicz

It seems that I used a wrong basic_format_context type when implementing the formatter. Perhaps we should consistently use basic_format_context<back_insert_iterator<_Fmt_buffer<_CharT>>, _Char> and copy format args by _Get_args.

I'd like to fix this after merging #4631 to avoid merge conflict.

frederick-vs-ja avatar May 03 '24 13:05 frederick-vs-ja

Not even a simple

    std::println( "{}", std::make_tuple( 1, 2, 3 ) );

seems to work. I'm confused. (VS 17.9.6, /std:c++latest)

https://godbolt.org/z/W3Yh6aT8P

nuuSolutions avatar May 14 '24 09:05 nuuSolutions

(VS 17.9.6, /std:c++latest)

tuple formatter will be available in VS 2022 17.9.11. It's a bit unfortunate that MSVC STL "trunk" is unavailable in Compiler Explorer.

frederick-vs-ja avatar May 14 '24 10:05 frederick-vs-ja