`<format>`: Underlying formatters of `pair-or-tuple` formatter cannot access format args
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)
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.
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
(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.