fmtlib / fmt

A modern formatting library
https://fmt.dev
Other
20.86k stars 2.51k forks source link

Compilation error: "'arg' is not a constant expression" #4242

Closed YanzhaoW closed 1 week ago

YanzhaoW commented 1 week ago

Error message

/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:2224:29: error: call to consteval function '(& cf)->fmt::v11::formatter<Option>::format<fmt::v11::context>(((qualified_type)(*(qualified_type*)arg)), (* & ctx))' is not a constant expression
 2224 |     ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
      |                    ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:2224:60: error: 'arg' is not a constant expression
 2224 |     ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));

Minimum example to reproduce

#include <fmt/format.h>

enum class Option { one, two, three };

constexpr auto convert_to_string(Option option) -> std::string_view {
    using enum Option;
    switch (option) {
        case one:
            return std::string_view{"one"};
        case two:
            return std::string_view{"tow"};
        case three:
            return std::string_view{"three"};
    }
}

template <>
class fmt::formatter<Option> {
   public:
    static constexpr auto parse(format_parse_context& ctx) { return ctx.end(); }
    template <typename FmtContent>
    constexpr auto format(Option option, FmtContent& ctn) const {
        return fmt::format_to(ctn.out(), convert_to_string(option));
    }
};

auto main() -> int {
    fmt::println("Option: {}", Option::one);
    return 0;

Godbolt link

[short link](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:12,endLineNumber:17,positionColumn:12,positionLineNumber:17,selectionStartColumn:12,selectionStartLineNumber:17,startColumn:12,startLineNumber:17),source:'%23include+%3Cfmt/format.h%3E%0A%0Aenum+class+Option+%7B+one,+two,+three+%7D%3B%0A%0Aconstexpr+auto+convert_to_string(Option+option)+-%3E+std::string_view+%7B%0A++++using+enum+Option%3B%0A++++switch+(option)+%7B%0A++++++++case+one:%0A++++++++++++return+std::string_view%7B%22one%22%7D%3B%0A++++++++case+two:%0A++++++++++++return+std::string_view%7B%22tow%22%7D%3B%0A++++++++case+three:%0A++++++++++++return+std::string_view%7B%22three%22%7D%3B%0A++++%7D%0A%7D%0A%0Atemplate+%3C%3E%0Aclass+fmt::formatter%3COption%3E+%7B%0A+++public:%0A++++static+constexpr+auto+parse(format_parse_context%26+ctx)+%7B+return+ctx.end()%3B+%7D%0A++++template+%3Ctypename+FmtContent%3E%0A++++constexpr+auto+format(Option+option,+FmtContent%26+ctn)+const+%7B%0A++++++++return+fmt::format_to(ctn.out(),+convert_to_string(option))%3B%0A++++%7D%0A%7D%3B%0A%0Aauto+main()+-%3E+int+%7B%0A++++fmt::println(%22Option:+%7B%7D%22,+Option::one)%3B%0A++++return+0%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:executor,i:(argsPanelShown:'1',compilationPanelShown:'0',compiler:g142,compilerName:'',compilerOutShown:'0',execArgs:'',execStdin:'',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!((name:fmt,ver:trunk)),options:'-std%3Dc%2B%2B23',overrides:!(),runtimeTools:!(),source:1,stdinPanelShown:'1',wrap:'1'),l:'5',n:'0',o:'Executor+x86-64+gcc+14.2+(C%2B%2B,+Editor+%231)',t:'0')),header:(),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4) [full link](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:12,endLineNumber:17,positionColumn:12,positionLineNumber:17,selectionStartColumn:12,selectionStartLineNumber:17,startColumn:12,startLineNumber:17),source:'%23include+%3Cfmt/format.h%3E%0A%0Aenum+class+Option+%7B+one,+two,+three+%7D%3B%0A%0Aconstexpr+auto+convert_to_string(Option+option)+-%3E+std::string_view+%7B%0A++++using+enum+Option%3B%0A++++switch+(option)+%7B%0A++++++++case+one:%0A++++++++++++return+std::string_view%7B%22one%22%7D%3B%0A++++++++case+two:%0A++++++++++++return+std::string_view%7B%22tow%22%7D%3B%0A++++++++case+three:%0A++++++++++++return+std::string_view%7B%22three%22%7D%3B%0A++++%7D%0A%7D%0A%0Atemplate+%3C%3E%0Aclass+fmt::formatter%3COption%3E+%7B%0A+++public:%0A++++static+constexpr+auto+parse(format_parse_context%26+ctx)+%7B+return+ctx.end()%3B+%7D%0A++++template+%3Ctypename+FmtContent%3E%0A++++constexpr+auto+format(Option+option,+FmtContent%26+ctn)+const+%7B%0A++++++++return+fmt::format_to(ctn.out(),+convert_to_string(option))%3B%0A++++%7D%0A%7D%3B%0A%0Aauto+main()+-%3E+int+%7B%0A++++fmt::println(%22Option:+%7B%7D%22,+Option::one)%3B%0A++++return+0%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:executor,i:(argsPanelShown:'1',compilationPanelShown:'0',compiler:g142,compilerName:'',compilerOutShown:'0',execArgs:'',execStdin:'',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!((name:fmt,ver:trunk)),options:'-std%3Dc%2B%2B23',overrides:!(),runtimeTools:!(),source:1,stdinPanelShown:'1',wrap:'1'),l:'5',n:'0',o:'Executor+x86-64+gcc+14.2+(C%2B%2B,+Editor+%231)',t:'0')),header:(),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4)

vitaut commented 1 week ago

The format string must be known at compile time, so you should change

return fmt::format_to(ctn.out(), convert_to_string(option));

to e.g.

return fmt::format_to(ctn.out(), "{}", convert_to_string(option));

See https://fmt.dev/11.0/api/#compile-time-checks for more details.

YanzhaoW commented 1 week ago

I see. Thanks.