I'm trying to write a custom std::fmt formatter for std::optional. Here's what I have so far:
#include
#include
#include
#include
#include
template
class fmt::formatter> {
public:
constexpr auto parse (format_parse_context& ctx) { return ctx.begin(); }
template
constexpr auto format (std::optional const& op, Context& ctx) const {
if(op) return format_to(ctx.out(), "{}", op.value());
else return format_to(ctx.out(), "-");
}
};
int main () {
std::vector> vec{{1}, {2}, {}};
fmt::print("{:}\n", vec);
// fmt::print("{:x}\n", vec); <----- SIGSEGV
}
The formatter works so long as I don't specify how the elements of the vector vec, i.e. the std::optionals, should be formatted. What I want to do is to specify how the uint64_ts should be formatted. In this example, I want them to formatted to hex strings. However, when I try to use my formatter with {:x}, I get a segfault.
Program returned: 139
terminate called after throwing an instance of 'fmt::v6::format_error'
what(): unknown format specifier
Program terminated with signal: SIGSEGV
I'm not sure how the std::format API works but based on what I could gather, I need to specify two functions for custom types: parse and format. The parse function is responsible for parsing the format specification, i.e. x}. It should consume all the tokens in the format specification that are relevant to it and then return the remaining format specification back. In my case I haven't specified the parse function, so it should return x} as it is (the default behavior of parse).
This remaining specification is then captured by ctx in format. If the op has a value, then the ctx and the value of op is returned. That's what format_to(ctx.out(), "{}", op.value()); does.
This logic seems sound to me, so I don't know why I'm getting a segfault. How should I modify my formatter to get it to do what I want it to do?