1

Motivation: I want to leverage the static (compile-time) error checking for string formatting from _format but cannot call it normally. My ideal solution would be a macro that will validate a static format string literal and the associated arguments, such as:

#include <fmt/format.h>
using namespace fmt::literals;

#define ENSURE_VALID(message, ...) message##_format(__VA_ARGS__)

// Examples
ENSURE_VALID("{} {}", 4, 5); // Will compile fine
ENSURE_VALID("{} {}", 3); // Will fail during compilation because not enough
                          // arguments were passed for the format string

Problem: The above implementation works for normal situations, but fails when the format string is defined elsewhere:

#define FMT_STR "{} {}"

ENSURE_VALID(FMT_STR, 4, 5); // Fails to compile

Calling ENSURE_VALID with FMT_STR fails because the preprocessor evaluates ENSURE_VALID before FMT_STR, resulting in FMT_STR_format, which is not expanded correctly.

What I am looking for: an implementation of ENSURE_VALID that correctly handles defined strings like FMT_STR.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
JimPri
  • 1,278
  • 8
  • 17
  • As you can tell from @Barry's valid answer, you just need to use standard C preprocessor voodoo here... nothing particular to C++20 or fmt. – einpoklum Dec 07 '20 at 23:13

2 Answers2

3

The usual solution here is just to use another macro:

#define ENSURE_VALID2(message, ...) message##_format(__VA_ARGS__)
#define ENSURE_VALID(message, ...) ENSURE_VALID2(message, __VA_ARGS__)

Just passing through message will allow it to properly expand inside of ENSURE_VALID2.

Barry
  • 286,269
  • 29
  • 621
  • 977
0

One solution I found is to append "" to the message string, creating:

#define ENSURE_VALID(message, ...) message""_format(__VA_ARGS__)

JimPri
  • 1,278
  • 8
  • 17