Skip to content
New issue

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

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

Already on GitHub? # to your account

Compile error with example from documentation #2522

Closed
matthieugras opened this issue Sep 29, 2021 · 7 comments
Closed

Compile error with example from documentation #2522

matthieugras opened this issue Sep 29, 2021 · 7 comments

Comments

@matthieugras
Copy link

matthieugras commented Sep 29, 2021

#include <fmt/format.h>

struct point { double x, y; };

template <> struct fmt::formatter<point> {
  // Presentation format: 'f' - fixed, 'e' - exponential.
  char presentation = 'f';

  // Parses format specifications of the form ['f' | 'e'].
  constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
    // [ctx.begin(), ctx.end()) is a character range that contains a part of
    // the format string starting from the format specifications to be parsed,
    // e.g. in
    //
    //   fmt::format("{:f} - point of interest", point{1, 2});
    //
    // the range will contain "f} - point of interest". The formatter should
    // parse specifiers until '}' or the end of the range. In this example
    // the formatter should parse the 'f' specifier and return an iterator
    // pointing to '}'.

    // Parse the presentation format and store it in the formatter:
    auto it = ctx.begin(), end = ctx.end();
    if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;

    // Check if reached the end of the range:
    if (it != end && *it != '}')
      throw format_error("invalid format");

    // Return an iterator past the end of the parsed range:
    return it;
  }

  // Formats the point p using the parsed format specification (presentation)
  // stored in this formatter.
  template <typename FormatContext>
  auto format(const point& p, FormatContext& ctx) -> decltype(ctx.out()) {
    // ctx.out() is an output iterator to write to.
    return format_to(
        ctx.out(),
        presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
        p.x, p.y);
  }
};

int main() {
  fmt::print("{}", point{1,2});
}

GCC fails with:

<source>:47:13:   required from here
<source>:39:21: error: 'this' is not a constant expression

This example from the documentation fails to compile with both GCC 11 and clang 12 but not in previous versions.

@matthieugras
Copy link
Author

Can reproduce the failure on master branch.

@Jerry-Ma
Copy link

I was having similar issues. The error is because fmtlib (>=8.0?) assumes constexpr for the format string.

To pass a runtime format string, this is needed: `fmt::format(fmt::runtime(some_runtime_string), ...).

@alexezeder
Copy link
Contributor

alexezeder commented Sep 29, 2021

The error is because fmtlib (>=8.0?) assumes constexpr for the format string

with C++20 enabled. I'm not sure why only GCC 11+ and Clang 12+ fail here, maybe a build system passes -std=c++20 for these versions.

Regarding passing a runtime format string, I can propose another option: keeping compile-time checks with one if.

Anyway, this example from documentation should be fixed if it's still available.

@matthieugras
Copy link
Author

Ok, thank you!

vitaut added a commit that referenced this issue Oct 2, 2021
@vitaut
Copy link
Contributor

vitaut commented Oct 2, 2021

The example is fixed now: https://fmt.dev/dev/api.html#formatting-user-defined-types. Thanks for reporting.

@avikivity
Copy link

Maybe the documentation is fixed, but how does one report an error during parsing? throw format_error fails since throw is not allowed in a constexpr function.

@vitaut
Copy link
Contributor

vitaut commented Jan 31, 2024

throw should work and give the desired behavior, either a compile-time error or a runtime error.

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

No branches or pull requests

5 participants