0

More specifically, how to insert a format string into another format string inside a macro? In other words, how to write

#define PRINT_ERROR(x, ...) do { if (DEBUG) fprintf(stderr, std::format("Error: {}\n", x).c_str(), __VA_ARGS__); } while (0)

without using sprintf or std::format (only available with /std:c++latest flag in MSVC as of the date of writing), i.e. not formatting the string twice in the first place?

#define PRINT_ERROR(x, ...) do { if (DEBUG) fputs("Error: ", stderr); fprintf(stderr, x, __VA_ARGS__); fputs("\n", stderr); } while (0)

is better, but that's three function calls instead of one.

Example:

const char* format = "%s %s!";
PRINT_ERROR(format, "Hello", "World");

Output:

Error: Hello World!

P.S.

I'm wrapping the macro inside a function anyway, but still want to have a fully functional macro for the sake of it.

class Debug final
{
public:
    template<typename... Args>
    static void Error(const std::string& fmt, Args... args) { PRINT_ERROR(fmt.c_str(), args...); }
    // ...
}
Trider
  • 13
  • 8
  • 2
    Setting aside the goal of being variadic, do you know about string literal concatenation? You can do `#define PRINT_ERROR(s) fputs("Error: " s "\n", stderr)` which will work as long as `s` is itself a string literal. – Nate Eldredge Jan 07 '22 at 03:27
  • Is there some reason that `PRINT_ERROR` *must* be a macro instead of just a template function? Why must it be a static class member instead of just a namespace scoped function? – Nicol Bolas Jan 07 '22 at 03:43
  • @NateEldredge, I know about this, but clearly it's not applicable to my case. – Trider Jan 07 '22 at 22:09
  • @o11c, no, it does not. – Trider Jan 07 '22 at 22:10
  • @NicolBolas, as I've said I just want to have a fully functional macro alongside with a function. As for class vs namespace question, the `Debug` class has some functionality that is better to be implemented via a class rather than namespace + globals. And separating a few of the functions into another namespace just for the sake of namespace'ness is not a good idea, imo. – Trider Jan 07 '22 at 22:20
  • Also, why the `C` tag was removed? Yes, I wrap the macro inside a `C++` function, but aside the `std::format` solution which is just one of the options, it's a pure `C` macro. – Trider Jan 07 '22 at 22:38
  • Well, speaking of literal concatenation, `#define PRINT_ERROR(fmt, ...) fprintf(stderr, "Error: " fmt "\n", __VA_ARGS__)` seems pretty close to what you want. You will get the desired effect from `PRINT_ERROR("%s %s!", "Hello", "World");`. You still can only use a literal for the format string, but that may be a good thing. – Nate Eldredge Jan 08 '22 at 16:03

0 Answers0