I have just upgraded our code base to using fmt 10, and have got into a strange problem.
Fmt introduces format_as
as a simple way of adding custom formatters for your own enums/classes, and also introduces formatting of std::optional
.
However, the combination of those two fails to compile using clang, but compiles fine using gcc or msvc. An example can be found here: godbolt. Change compiler to gcc and the code compiles fine.
#include <fmt/format.h>
#include <fmt/std.h>
#include <optional>
namespace nn
{
enum class Bar
{
First,
Second,
Third,
Fifth = 5,
};
std::string_view format_as(Bar bar)
{
switch (bar) {
case Bar::First:
return "One";
case Bar::Second:
return "Two";
case Bar::Third:
return "Three";
case Bar::Fifth:
return "Five";
}
return "";
}
}
int main() {
auto b = nn::Bar::First;
std::optional<nn::Bar> ob = b;
fmt::print("{} {}\n", b, ob);
return 0;
}
The problem seems to be that "fmt/std.h" calls u.set_debug_format(set);
on line 170, and set_debug_format
is private due to the private inheritance in fmt/format.h line 4055. If I add using base::set_debug_format;
on line 4058, the code compiles also on clang.
Have anybode else stumled into this problem? Is it a bug in fmt, or a problem with the clang compiler, or me just doing something wrong?
Yes, this is a bug in clang, reported at https://github.com/llvm/llvm-project/issues/68849. As discussed in https://github.com/scylladb/seastar/pull/1855, the workaround is to publicly inherit from the base formatter; in your case:
Demo.
Note that this will change the output from
optional(One)
tooptional("One")
since the change to public inheritance will allowparse
to callbase::set_debug_format()
; however, this is arguably preferable behavior for fmt.