Reputation: 30128
I am looking for a way to implement format_as
for a enum class inside templated class without having to use forwarder wrapper for every instantiation.
For example this works:
template<typename T>
auto format_as_impl(typename S<T>::Side side) {
switch(side) {
case S<T>::Side::Left:
return "L";
case S<T>::Side::Right:
return "R";
};
__builtin_unreachable();
}
auto format_as(const typename S<int>::Side& side) {
return format_as_impl<int>(side);
}
auto format_as(const typename S<double>::Side& side) {
return format_as_impl<double>(side);
}
but trying to make this work generically blows up
template<typename T>
auto format_as(typename S<T>::Side side) {
switch(side) {
case S<T>::Side::Left:
return "L";
case S<T>::Side::Right:
return "R";
};
__builtin_unreachable();
}
In file included from /opt/compiler-explorer/libs/fmt/10.2.1/include/fmt/format.h:49, from :9: /opt/compiler-explorer/libs/fmt/10.2.1/include/fmt/core.h: In instantiation of 'constexpr decltype (ctx.begin()) fmt::v10::detail::parse_format_specs(ParseContext&) [with T = S::Side; ParseContext = compile_parse_context; decltype (ctx.begin()) = const char*]': /opt/compiler-explorer/libs/fmt/10.2.1/include/fmt/core.h:2684:51:
required from here :44:15: in 'constexpr' expansion of 'fmt::v10::basic_format_string<char, S::Side, S::Side, S::Side>("{} {} {}\012")'
If it matters I am using libfmt 10.2.1 since I know they changed something wrt enums recently, but that does not seem like what is affecting me. godbolt
Upvotes: 1
Views: 386
Reputation: 15918
The left side of ::
is a non-deduced context, which means the template parameter T
in S<T>::Side
can never be deduced. It must be explicitly provided when calling this function template, which fmtlib is not able to do. Thus, the function template format_as
in question cannot be used by fmtlib.
I would recommend making format_as
a friend function defined in S
(the "hidden friend" idiom).
template<typename T>
struct S {
// ...
friend auto format_as(Side side) {
switch(side) {
case Side::Left:
return "L";
case Side::Right:
return "R";
};
__builtin_unreachable();
}
};
Upvotes: 3