I'm trying to format binary data into its hexadecimal representation, using fmt::join with FMT_COMPILE.
From the documentation, I'd expect this program to do the job:
#include "fmt/core.h"
#include "fmt/compile.h"
int main() {
unsigned char data[] = {0x1, 0x2};
auto s = fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, ""));
}
However, starting at v8.0.0, it gives the following error when compiling:
error on g++ (Ubuntu 11.2.0-7ubuntu2) 11.2.0:
$ g++ -std=gnu++20 -o main test.cpp
In file included from test.cpp:2:
fmt/compile.h: In instantiation of ‘constexpr OutputIt fmt::v8::detail::spec_field<Char, T, N>::format(OutputIt, const Args& ...) const [with OutputIt = std::back_insert_iterator<std::__cxx11::basic_string<char> >; Args = {fmt::v8::join_view<unsigned int*, unsigned int*, char>}; Char = char; T = fmt::v8::join_view<unsigned int*, unsigned int*, char>; int N = 0]’:
fmt/compile.h:546:3: required from ‘std::__cxx11::basic_string<Char> fmt::v8::format(const CompiledFormat&, const Args& ...) [with CompiledFormat = fmt::v8::detail::spec_field<char, fmt::v8::join_view<unsigned int*, unsigned int*, char>, 0>; Args = {fmt::v8::join_view<unsigned int*, unsigned int*, char>}; Char = char; typename std::enable_if<fmt::v8::detail::is_compiled_format<T>::value, int>::type <anonymous> = 0]’
fmt/compile.h:579:18: required from ‘std::__cxx11::basic_string<typename S::char_type> fmt::v8::format(const S&, Args&& ...) [with S = main()::<lambda()>::FMT_COMPILE_STRING; Args = {fmt::v8::join_view<unsigned int*, unsigned int*, char>}; typename std::enable_if<fmt::v8::detail::is_compiled_string<S>::value, int>::type <anonymous> = 0; typename S::char_type = char; typename Context::char_type = char]’
test.cpp:6:25: required from here
fmt/compile.h:313:22: error: passing ‘const fmt::v8::formatter<fmt::v8::join_view<unsigned int*, unsigned int*, char>, char, void>’ as ‘this’ argument discards qualifiers [-fpermissive]
313 | return fmt.format(get_arg_checked<T, N>(args...), ctx);
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from fmt/compile.h:11,
from test.cpp:2:
fmt/format.h:2821:8: note: in call to ‘decltype (ctx.out()) fmt::v8::formatter<fmt::v8::join_view<It, Sentinel, Char>, Char>::format(const fmt::v8::join_view<It, Sentinel, Char>&, FormatContext&) [with FormatContext = fmt::v8::basic_format_context<std::back_insert_iterator<std::__cxx11::basic_string<char> >, char>; It = unsigned int*; Sentinel = unsigned int*; Char = char; decltype (ctx.out()) = std::back_insert_iterator<std::__cxx11::basic_string<char> >]’
2821 | auto format(const join_view<It, Sentinel, Char>& value, FormatContext& ctx)
| ^~~~~~
error on clang++ 13 (Ubuntu clang version 13.0.0-2):
$ clang++ -std=gnu++20 -o main test.cpp
In file included from test.cpp:2:
./fmt/compile.h:313:16: error: no matching member function for call to 'format'
return fmt.format(get_arg_checked<T, N>(args...), ctx);
~~~~^~~~~~
./fmt/compile.h:546:6: note: in instantiation of function template specialization 'fmt::detail::spec_field<char, fmt::join_view<unsigned int *, unsigned int *>, 0>::format<std::back_insert_iterator<std::basic_string<char>>, fmt::join_view<unsigned int *, unsigned int *>>' requested here
cf.format(std::back_inserter(s), args...);
^
./fmt/compile.h:579:12: note: in instantiation of function template specialization 'fmt::format<fmt::detail::spec_field<char, fmt::join_view<unsigned int *, unsigned int *>, 0>, fmt::join_view<unsigned int *, unsigned int *>, char, 0>' requested here
return format(compiled, std::forward<Args>(args)...);
^
test.cpp:6:19: note: in instantiation of function template specialization 'fmt::format<FMT_COMPILE_STRING, fmt::join_view<unsigned int *, unsigned int *>, 0>' requested here
auto s = fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, ""));
^
./fmt/format.h:2821:8: note: candidate function template not viable: 'this' argument has type 'const formatter<fmt::join_view<unsigned int *, unsigned int *>, char>', but method is not marked const
auto format(const join_view<It, Sentinel, Char>& value, FormatContext& ctx)
^
1 error generated.
On 7.1.3, it worked fine. When removing the compilation, it also works fine. When removing the format specifier ({:02x} -> {}), it also works
The changelogs for version 8.0.0 included this note:
Format string compilation now requires format functions of formatter specializations for user-defined types to be const:
template <> struct fmt::formatter<my_type>: formatter<string_view> {
template <typename FormatContext>
auto format(my_type obj, FormatContext& ctx) const { // Note const here.
// ...
}
};
However, from what I understand, I'm not using a user defined formatter.
Annotating the format method in fmt/format.h:2821 with the const qualifier (however little sense this might make) makes the compilation pass.
Am I doing something wrong, or is this a bug?
I'm trying to format binary data into its hexadecimal representation, using
fmt::joinwithFMT_COMPILE.From the documentation, I'd expect this program to do the job:
However, starting at v8.0.0, it gives the following error when compiling:
error on g++ (Ubuntu 11.2.0-7ubuntu2) 11.2.0:
error on clang++ 13 (Ubuntu clang version 13.0.0-2):
On 7.1.3, it worked fine. When removing the compilation, it also works fine. When removing the format specifier (
{:02x}->{}), it also worksThe changelogs for version 8.0.0 included this note:
However, from what I understand, I'm not using a user defined formatter.
Annotating the
formatmethod in fmt/format.h:2821 with theconstqualifier (however little sense this might make) makes the compilation pass.Am I doing something wrong, or is this a bug?