Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
JMazurkiewicz opened this issue May 3, 2024 · 3 comments · May be fixed by #4681
Open

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

JMazurkiewicz opened this issue May 3, 2024 · 3 comments · May be fixed by #4681
Labels
bug Something isn't working format C++20/23 format

Comments

@JMazurkiewicz
Copy link
Contributor

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)
@frederick-vs-ja
Copy link
Contributor

frederick-vs-ja commented May 3, 2024

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.

@StephanTLavavej StephanTLavavej added bug Something isn't working format C++20/23 format labels May 8, 2024
@nuuSolutions
Copy link

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

@frederick-vs-ja
Copy link
Contributor

(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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working format C++20/23 format
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants