-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Regression in formatting a type through a pointer using specialization #3157
Comments
Formatting of non-void pointers is intentionally disallowed. If you want to format a pointer cast it to |
@vitaut Can I ask why? It seems very unfriendly to shunt all the work of trying to safely dereference onto the individual fmt uses, rather than leaving it in one place (in the specialization). Here's an example, which used to work just fine: class MyClass
{
public:
int thing = 42;
};
namespace fmt {
template <>
struct formatter<MyClass*>
{
constexpr auto parse(format_parse_context& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const MyClass* const value, FormatContext& ctx)
{
if (value) {
return format_to(ctx.out(), "MyClass(this: {}, thing={})", (void*)value, value->thing);
} else {
return format_to(ctx.out(), "MyClass(this: nullptr)");
}
}
};
} Test code (dbg is just my own light-weight wrapper to print using fmt, it's not really relevant): MyClass* m1 = nullptr;
MyClass* m2 = new MyClass;
dbg("test! {}", m1);
dbg("test! {}", m2); (Past) output:
If we do it your way, and dereference: dbg("test! {}", *m1); ... this will now immediately crash. It's easily fixed in this contrived case, sure, but imagine you're printing a tree node where you have multiple pointers to try output, that's going to get awkward pretty fast. I suppose a benefit is that with a specialization on the pointer, you can't (easily?) use fmt without a pointer, but it was always trivial to get one: MyClass m3;
dbg("test! {}", m3); // this won't compile
dbg("test! {}", &m3); // but this will |
It was an early design decision based on the fact that pointer formatting has a separate semantics from value formatting but unfortunately there was a regression in enforcing it. Basically the same reasoning as discussed in https://accu.org/journals/overload/17/89/wilson_1539/. You can achieve similar behavior via an adapter type which is the usual extension mechanism in {fmt}. So the recommended solution is to define a MyClass m3;
dbg("test! {}", m3);
dbg("test! {}", ptr(&m3)); |
It seems that after the fix for #2717 (8f8a1a0), it seems it is no longer possible to specialize
formatter
for a given pointer type:Reproduced on godbolt here: https://godbolt.org/z/h3cWYYev8.
Though I notice that even just reverting that commit isn't quite enough, as the specialization doesn't seem to get used anymore. It certainly used to work in fmt 8.1.1 - I'm not quite sure when that broke.
Is this intentional? It seems like a pretty inconvenient behaviour change.
The text was updated successfully, but these errors were encountered: