Update: See Compile-time format string checks for a better solution that doesn’t involve macros.
As an author of C++ Format, a library that
implements safe Python-like and printf-like formatting, every now and then I hear
questions whether it supports compile-time checking of format strings and arguments.
Until recently I didn’t know any way to do this, but then it occurred to me that it
is possible to have some compile-time checking based on GCC’s
This approach is somewhat limited and not particularly elegant, but it can be
useful in some cases such as logging.
If you are not familiar with the GCC’s
format attribute, here’s an example demonstrating
how it works:
This is a pretty nice but, of course, only works with literal format strings.
format attribute requires varargs and doesn’t support variadic
and for obvious safety reasons C++ Format avoids varargs.
The main (and ugly) part of the solution is to use a macro with a call to a dummy vararg function
declared with the
format attribute and a call to the actual formatting function
check_args function is never called, so it doesn’t introduce runtime overheads or
safety issues. But it makes the compiler do its magic:
One of the limitations of this method is that it can’t be used with objects of
non-trivially-copyable C++ types such as
std::string passed as formatting arguments.
Of course, this only gives a compile-time diagnostic for literal format string, but C++ Format got you covered in all cases with runtime type checking which is relatively cheap. Also if you use Python-like format strings, you can often omit type specifier in the format string which makes the check unnecessary:
The approach described in this post has been successfully applied in the logging system of TrinityCore, a well-known open-source MMO framework.