NoSenseEtAl
NoSenseEtAl

Reputation: 30128

format_as with fmt enum class inside templated class

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

Answers (1)

cpplearner
cpplearner

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

Related Questions