-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
using custom formatter for types with stream operator #952
Comments
I feel your pain. This was one of the topics of my talk at Meeting C++ 2018. Given it's current architecture of custom formatters, afaik there is no way to make user-supplied custom formatters more specialized than the one automatically generated by I'd love to see a better way to work around this migration roadblock. |
If you don't care about multiple character type support and can fully specialize #include <iostream>
#include <fmt/ostream.h>
struct S {};
std::ostream& operator<<(std::ostream& os, S) {
return os << 1;
}
template <>
struct fmt::formatter<S> : fmt::formatter<int> {
template <typename FormatContext>
auto format(S, FormatContext& ctx) {
return formatter<int>::format(2, ctx);
}
};
int main() {
std::cout << S() << "\n"; // prints 1
fmt::print("{}\n", S()); // prints 2
} It should be possible to make it work with partial specializations too by not having ostream support plug into the general extension API, but using a separate lower-priority extension point. This will require some changes to {fmt}. |
I would suggest adding a simple trait |
There is already such trait called |
Thank you all for the insights. So basically there is no easy (at least not difficult) way to achieve this. I guess I'll just stick to what we have and use the wrapper object. @vitaut I don't think is_streamable would work for me because what I would like to do is to make an already existing streamable class to act as if it is not streamable, so my custom formatter would be used in format. @foonathan you option would work if this enable_ostream trait is some magic on the |
You can use #include <iostream>
#include <fmt/ostream.h>
template <typename T>
struct S {};
template <typename T>
std::ostream& operator<<(std::ostream& os, S<T>) {
return os << 1;
}
template <typename T>
struct fmt::formatter<S<T>> : fmt::formatter<int> {
template <typename FormatContext>
auto format(S<T>, FormatContext& ctx) {
return formatter<int>::format(2, ctx);
}
};
template <typename T>
struct fmt::internal::is_streamable<S<T>, char>
: std::false_type {};
int main() {
std::cout << S<int>() << "\n"; // prints 1 using operator<<
fmt::print("{}\n", S<int>()); // prints 2 using formatter
} |
#include <iostream>
#include <fmt/ostream.h>
template <typename T>
struct S {};
template <typename T>
std::ostream& operator<<(std::ostream& os, S<T>) {
return os << 1;
}
template <typename T>
struct fmt::formatter<S<T>> : fmt::formatter<int> {
auto format(S<T>, format_context& ctx) {
return formatter<int>::format(2, ctx);
}
};
int main() {
std::cout << S<int>() << "\n"; // prints 1 using operator<<
fmt::print("{}\n", S<int>()); // prints 2 using formatter
} |
Hi,
I am trying to let
fmt::format("{}", m)
to make use of the custom formatter as described in the API doc by defining specialization of the template classfmt::formatter
with m's typeM
.However,
M
is from a third party library (to be specific, in my caseM
isEigen::EigenBase<Derived>
) that has itsoperator <<
defined.Not including
fmt/ostream.h
is not an option for me because I do want the types that doesn't comes with afmt::formatter
specialization fall back to use itsoperator <<
.But, if I include
fmt/ostream.h
, it will simply shadow my partial specialization offmt::formatter<M, Char>
, and callingfmt::format("{}", m)
will just beos << m
.The current solution I came up with is to define a wrapper class
pprint<M>(M m)
so that I can dofmt::format("{}", pprint(m))
, but this looks cumbersome.Could you please help on this?
The text was updated successfully, but these errors were encountered: