Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using FMT_COMPILE with format specifiers for fmt::join gives compilation errors about constness. #2719

Closed
richardebeling opened this issue Jan 14, 2022 · 2 comments

Comments

@richardebeling
Copy link

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?

@vitaut
Copy link
Contributor

vitaut commented Jan 14, 2022

fmt::join is incompatible with format string compilation but it's easy to change by making this function const:

fmt/include/fmt/format.h

Lines 2820 to 2822 in 58fb782

template <typename FormatContext>
auto format(const join_view<It, Sentinel, Char>& value, FormatContext& ctx)
-> decltype(ctx.out()) {

A PR would be welcome.

@phprus
Copy link
Contributor

phprus commented Jan 14, 2022

@vitaut, PR #2720

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants