I have the following template to use fmt to format a user-defined type:
#include "fmt/format.h"
struct MyClass
{
operator std::string() const
{
return "xyz";
}
};
template <> struct fmt::formatter<MyClass>
{
template <typename ParseContext> constexpr auto parse(ParseContext& ctx) const {
return ctx.begin();
}
template <typename FormatContext> constexpr auto format(const MyClass& c, FormatContext& ctx) const {
return format_to(ctx.out(), "{}", (std::string)c);
}
};
I attempted to template and instantiate this template specialization:
template <typename T> template <> struct fmt::formatter<T>
{
template <typename ParseContext> constexpr auto parse(ParseContext& ctx) const {
return ctx.begin();
}
template <typename FormatContext> constexpr auto format(const T& t, FormatContext& ctx) const {
return format_to(ctx.out(), "{}", (std::string)t);
}
};
template struct fmt::formatter<MyClass>;
I get error C2913: explicit specialization; 'fmt::v7::formatter<MyClass,char,void>' is not a specialization of a class template.
How can I accomplish this, or some other way to make it simpler to turn a type with overloaded operator std::string() into a type that can be formatted?
If you want to have re-usable formatter that you can explicitly define for any class, the easiest thing to do would be to define a base class and derive
fmt::formatter<T>from it:Demo
If instead you want to define a formatter that automatically applies to any class that can be converted to
std::string, then you need to use either C++20 concepts or some form of SFINAE.Possible C++20 concepts implementation:
Demo
And a possible C++17 SFINAE-based solution:
Demo