Open AA1999 opened 6 months ago
User-defined types must opt in to being formatted by std::format
by specializing std::formatter
. https://en.cppreference.com/w/cpp/utility/format/formatter
fmt::format
is probably picking up implicit conversions, which means that it can get them very very wrong. What happens if you have a json file with numbers instead of strings? Does fmt::format
display them properly? I would be very surprised, unless someone added support for this specific library.
I assume that std::format
explicitly excludes implicit conversions to types that std::formatter
is enabled for, which is much safer.
For some reason now fmt is also now not working (I'm pretty sure it did before, maybe an earlier version)
In file included from test.cpp:4:
In file included from /usr/include/fmt/format.h:49:
/usr/include/fmt/core.h:2548:45: error: implicit instantiation of undefined template 'fmt::detail::type_is_unformattable_for<nlohmann::basic_json<>, char>'
type_is_unformattable_for<T, char_type> _;
^
/usr/include/fmt/core.h:2611:23: note: in instantiation of function template specialization 'fmt::detail::parse_format_specs<nlohmann::basic_json<>, fmt::detail::compile_parse_context<char>>' requested here
parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
^
/usr/include/fmt/core.h:2740:47: note: in instantiation of member function 'fmt::detail::format_string_checker<char, nlohmann::basic_json<>, nlohmann::basic_json<>>::format_string_checker' requested here
detail::parse_format_string<true>(str_, checker(s));
^
test.cpp:9:27: note: in instantiation of function template specialization 'fmt::basic_format_string<char, nlohmann::basic_json<> &, nlohmann::basic_json<> &>::basic_format_string<char[6], 0>' requested here
std::cout << fmt::format("{} {}", data.at("host"), data.at("port"));
^
/usr/include/fmt/core.h:1554:45: note: template is declared here
template <typename T, typename Char> struct type_is_unformattable_for;
^
test.cpp:9:27: error: call to consteval function 'fmt::basic_format_string<char, nlohmann::basic_json<> &, nlohmann::basic_json<> &>::basic_format_string<char[6], 0>' is not a constant expression
std::cout << fmt::format("{} {}", data.at("host"), data.at("port"));
^
In file included from test.cpp:4:
In file included from /usr/include/fmt/format.h:49:
/usr/include/fmt/core.h:1576:63: error: implicit instantiation of undefined template 'fmt::detail::type_is_unformattable_for<nlohmann::basic_json<>, char>'
type_is_unformattable_for<T, typename Context::char_type> _;
^
/usr/include/fmt/core.h:1808:23: note: in instantiation of function template specialization 'fmt::detail::make_arg<true, fmt::basic_format_context<fmt::appender, char>, nlohmann::basic_json<>, 0>' requested here
data_{detail::make_arg<is_packed, Context>(args)...} {
^
/usr/include/fmt/core.h:1826:10: note: in instantiation of function template specialization 'fmt::format_arg_store<fmt::basic_format_context<fmt::appender, char>, nlohmann::basic_json<>, nlohmann::basic_json<>>::format_arg_store<nlohmann::basic_json<>, nlohmann::basic_json<>>' requested here
return {args...};
^
/usr/include/fmt/core.h:2788:28: note: in instantiation of function template specialization 'fmt::make_format_args<fmt::basic_format_context<fmt::appender, char>, nlohmann::basic_json<>, nlohmann::basic_json<>>' requested here
return vformat(fmt, fmt::make_format_args(args...));
^
test.cpp:9:20: note: in instantiation of function template specialization 'fmt::format<nlohmann::basic_json<> &, nlohmann::basic_json<> &>' requested here
std::cout << fmt::format("{} {}", data.at("host"), data.at("port"));
^
/usr/include/fmt/core.h:1554:45: note: template is declared here
template <typename T, typename Char> struct type_is_unformattable_for;
^
/usr/include/fmt/core.h:1579:3: error: static assertion failed due to requirement 'formattable': Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
static_assert(
^
4 errors generated.
Anyhow then ig nlohmann::json
would need a std::formatter
?
Anyhow then ig nlohmann::json would need a std::formatter?
Yes. I assume, but can't say for sure, that a PR would be welcome as long as it was sufficient protected such that it didn't affect the ability to build as C++11. There are other features that are conditionally available based on the C++ standard in use. @nlohmann would have the final say on that.
As far as I'm aware there are micros to check C++ version and not define a function if it's not matching, so maybe this could be added only if c++20 flag is added.
Yes, this library has JSON_HAS_CPP_20
for that.
I ran into this when updating dependencies.
For fmt you can observe this break in this godbolt example: https://godbolt.org/z/jx7fTen7Y
with fmt 9.1.0 it works, with 10.0.0 it still compiles but throws and with 10.1.1 it finally doesn't compile anymore.
I guess something like this would fix the issue for std::format
#if defined(JSON_HAS_CPP_20) && __has_include(<format>)
#include <format>
template <>
struct std::formatter<json> {
constexpr auto parse(std::format_parse_context& ctx) {
return ctx.begin();
}
auto format(const json& j, std::format_context& ctx) const {
return std::format_to(ctx.out(), "{}", to_string(j));
}
};
#endif
but this doesn't fix it for fmt :(.
To implement a formatter which would work from fmt 10.0.0 onwards it would suffice to implement format_as
as follows:
namespace nlohmann {
auto format_as(const json& j) { return j.dump(); }
}
Godbolt: https://godbolt.org/z/vEEad83h3
Description
I've opened a json file and parsed it with this library and I wrote this:
However I get this error:
Note of interest: this only happens with std::format, fmt::format is fine
Reproduction steps
Open a file with std::ifstream Pass the file object to nlohmann::json Parse the json file Try to format it using std::format
Expected vs. actual results
Expected result: The json array being formatted properly Actual result: error
Minimal code example
Error messages
Compiler and operating system
clang 17, linux
Library version
3.11.2
Validation
develop
branch is used.