c++printfvariadic-templates

Variadic template with printf argument checking


I have a printf-style function that takes a variable number of arguments. Here is my starting point:

#include <stdio.h>
#include <stdarg.h>
void MyPrint (const char* fmt,...)
  {
  va_list arglist ;
  va_start (arglist, fmt) ;
  vprintf (fmt, arglist) ;
  va_end (arglist) ;
  }

int main()
  {
  MyPrint ("Hello, %s\n", "world") ;
  }

This prints Hello, world as expected.

Now I want to make two changes. First, I want to check the format string using the format attribute of g++. So I declare the MyPrint function first (I have to declare it first, because for some reason g++ doesn't let you assign attributes to a function definition):

void MyPrint (const char* fmt,...) __attribute__ ((format (printf, 1, 2))) ;

Now if I try e.g. MyPrint ("Hello, %d\n", "world") ; I get a nice error message.

The second change I want to make is to use a variadic template parameter. Like this:

#include <utility> // for std::forward
template<typename...Params>
void MyPrint (Params&&... fmt)
  {
  printf (std::forward<Params> (fmt)...) ;
  }

This works too. So I combine the two, by adding the format-checking attribute to the variadic function template with this forward declaration:

template<typename...Params>
void MyPrint (Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;

But now I get this error message (gcc 10.2):

<source>: In substitution of 'template<class ... Params> void MyPrint(Params&& ...) [with Params = {const char (&)[11], const char (&)[6]}]':
<source>:15:38: required from here
<source>:8:6: error: 'format' attribute argument 2 value '1' refers to parameter type 'const char (&)[11]'

This has got me completely baffled. Can anybody tell me what I'm doing wrong?

Here is the complete program:

#include <stdio.h>
#include <utility> // for std::forward

template<typename...Params>
void MyPrint (Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;

template<typename...Params>
void MyPrint (Params&&... fmt) // <-- Line 8
  {
  printf (std::forward<Params> (fmt)...) ;
  }

int main()
  {
  MyPrint ("Hello, %s\n", "world") ; // <-- Line 15
  }

Solution

  • Just for info: this has been fixed in gcc 13.1. The program works as expected, with no compiler errors or warnings.