6

I use the ROOT C++ libraries (root.cern.ch) daily and was browsing the source when I came across this function declaration:

TString TString::Format(const char *va_(fmt), ...)
{
    //etc.

It can be found here.

I don't understand how a const char * can have an argument or a parenthesis in its name. The expression va_(fmt) is later used as a simple const char * even though it looks like a function call or a constructor. At first I thought it had something to do with the variable argument list, which was also new to me, but reading documentation on stdarg.h didn't help with this question at all.

It is very hard to google for help since I'm not really sure what to call this. A declaration with an argument? That doesn't give any good results.

I used to think I knew C++, but what is going on here? All help will be appreciated.

Simon
  • 961
  • 2
  • 9
  • 14

1 Answers1

11

It's a macro - in Varargs.h:

#if ...
#  define va_(arg) __builtin_va_alist
#else
#  define va_(arg) arg
#endif
JoeG
  • 12,994
  • 1
  • 38
  • 63
  • 7
    We tell C programmers that `#define` just obfuscates, but do they believe us? *No...* ^_- – Mike DeSimone Mar 20 '12 at 14:35
  • Another example of why macros are bad. If `fmt` were a type then the syntax would be a valid declaration of a function taking, as an argument named `va_`, a pointer to a function returning `char const *`. – bames53 Mar 20 '12 at 14:42
  • How does this even make any difference in the function in question, compared to just naming the parameter `va_fmt`? – leftaroundabout Mar 20 '12 at 14:53
  • @leftaroundabout Joe leaves out the clause on the `#if`. It's probably something like `#if SOME_FANCY_OPTIMIZED_STDARG_COMPILER_OPTION_ENABLED`. What this code does is give you `TString TString::Format(const char *__builtin_va_alist, ...)` if the fancy compiler option is enabled, or `TString TString::Format(const char *fmt, ...)` if not. There's no `va_fmt` anywhere. – Mike DeSimone Mar 20 '12 at 14:57
  • @MikeDeSimone: yeah I know. The thing is, inside the function the parameter is only ever called through the macro, there's no plain `__builtin_va_list` or `fmt`. So regardless of what the macro expands to, that name will turn up, shadow any variable with the same name outside the function, and lead to exactly the same behaviour regardless what the name is. That's what I think, but obviously I'm missing something. – leftaroundabout Mar 20 '12 at 15:10
  • What you're missing is that the compiler treats `__builtin_va_list` specially, and not as a straight forward parameter name. Generally, anything starting with a double underscore is compiler secret sauce. – Mike DeSimone Mar 20 '12 at 22:14