-1

I'm trying to create a logging function, that will write formatted string to a buffer. The function should automatically add source code location to the formatted string using std::source_location. The formatting function format_to requires the formating string is constant expression. The signature of the format_to function is simplified in the example.

#include <source_location>
#include <string_view>
#include <cstdint>

struct format_string_with_location {
  consteval format_string_with_location(const char* s, const std::source_location& l = std::source_location::current()) :
      str(s), loc(l)
      {}

  std::string_view str;
  std::source_location loc;
};

struct format_string {
  template<typename T>
  consteval format_string(const T& t) : str{t} {}

  std::string_view str;
};

template<typename...Args>
void format_to(format_string str, Args&&...) {}

template<typename... Args>
void debug(format_string_with_location format, const Args&... args)
{
    format_to("{} {}:", format.loc.file_name(), format.loc.line());
    format_to(format.str, args...);
}

int main() {
    debug("error: {}", 42);
}

Demo

format_to("error {}", 42);

works as expected, but

debug("error: {}", 42);

fails to compile with following error:

<source>: In instantiation of 'void debug(format_string_with_location, const Args& ...) [with Args = {int}]':
<source>:31:10:   required from here
<source>:27:14:   in 'constexpr' expansion of 'format_string(format.format_string_with_location::str)'
<source>:27:14: error: 'format' is not a constant expression
   27 |     format_to(format.str, args...);
      |     ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~

How to fix it?

0

2 Answers 2

0

Parameters are not constexpr (even in consteval functions, or with consteval type).

You might reorganize your code as follow though:

struct format_string {
  template<typename T>
  consteval format_string(const T& t) : str{t} {}

  std::string_view str;
};

struct format_string_with_location {
  consteval format_string_with_location(
     const char* s,
     const std::source_location& l = std::source_location::current()) :
      str(s), loc(l)
      {}

  format_string str;
  std::source_location loc;
};

Demo

You no longer construct a format_string with parameter.

Sign up to request clarification or add additional context in comments.

2 Comments

This however does not work if the format_string is template class. How to modify it to work with fmt::print() ? godbolt.org/z/T5zYG1W9o
Ok, with {fmt} I can use the vprintf together with make_format_args. But unfortunately this does not work with the "emio" library I'm trying to use. It also supports make_format_args, but it still requires constexpr format :-(
0

consteval - "every potentially-evaluated call to the function must (directly or indirectly) produce a compile time constant expression."

You could change the format_string constructor to constexpr:

struct format_string {
    template <typename T>
    constexpr format_string(const T& t) : str{t} {}

    std::string_view str;
};

Then the following would work:

template <typename... Args>
void format_to(format_string str, Args&&... args) {
    std::cout << std::vformat(str.str, std::make_format_args(args...));
}

template <typename... Args>
void debug(format_string_with_location format, const Args&... args) {
    format_to("{} {}:", format.loc.file_name(), format.loc.line());
    format_to(format.str, args...);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.