0

I have a function:

SendMsg(int x, string y, ...) { /*some code*/ }

I have a macro:

FOO(X, STRING, ...) SendMsg(X, STRING "%s %d", ##__VA_ARGS__, "xyz", 123)

so I can have something like this:

FOO(1000, "Note that line %d containing %d words is invalid", 5, 10);

expanded to

SendMsg(1000, "Note that line %d containing %d words is invalid" "%s %d", 5, 10, "xyz", 123);

At times I have something like this:

FOO(1000, "String without variables");

which should be expanded as

SendMsg(1000, "String without variables" "%s %d", "xyz", 123)

The macro works fine so far.

But at times I have something like this:

FOO(1000);

which should be expanded as

SendMsg(1000, "%s "%d", "xyz", 123);

But this does not work. I get an error that "macro FOO requires 3 arguments, but only 1 given". Any ideas?

user2524261
  • 109
  • 2
  • 10
  • cant you pass empty string as 2nd argument to the macro? – rahul.deshmukhpatil Dec 10 '15 at 09:32
  • I want to avoid doing that. Or introduce another macro that will do that. – user2524261 Dec 10 '15 at 09:41
  • In that case macro could only contain only 1st argument as fixed one. While starting from 2nd all are variadic. So in the macro itself, you could extract 2nd argument to macro separately and pass it as 2nd argument of the SendMsg. while 3rd argument to fucntion will be "%s %d" and then all the remaining variadics + "xyz" + 123. – rahul.deshmukhpatil Dec 10 '15 at 09:49
  • how do I extract the second argument? and how do I obtain all the remaining variadics? – user2524261 Dec 10 '15 at 09:52

2 Answers2

0

what you need to do is change the signature of the SendMsg.

SendMsg(int x, char *secondFmt, char *xyx, int no123, ...)
{
     // Print the string in buffer with ##__VA_ARGS__ using sprintf. first 
     // argument extracted from will be string only. otherwise sprintf will fail
     va_start(args, no123);
     const char *fmt = va_arg(args, const char *);
     bytesWrote = sprintf(buffer, fmt, args);
     sprintf(buffer + bytesWrote, secondFmt, xyz, no123);
     va_end(args);
}

Now Foo will look like

FOO(X, ...) SendMsg(X, "%s %d", "xyz", 123, ##__VA_ARGS__)

What I did is I printed message from ##__VA_ARGS__ first and then "%s %d" part. in the reverse order how arguments are provided to SendMsg. Untested, so just tune code.

If you do not want to modify the SendMsg, see if below code works.

 FOO(X, ...) {\
  va_start(args, no123);\
  const char *fmt = va_arg(args, const char *);\
  SendMsg(X, fmt "%s %d", "xyz", 123, args);\
  va_end(args);\
}\

if not, just write two macros, :

FOO_FMT(X, STRING, ...) SendMsg(X, STRING"%s %d", "xyz", 123, ##__VA_ARGS__)
FOO(X) SendMsg(X, "%s %d", "xyz", 123)
rahul.deshmukhpatil
  • 977
  • 1
  • 16
  • 31
0

With variadic template (C++11), you may do overloads, something like:

template <typename... Ts>
void FOO(int x, const std::string& format, Ts... args)
{
    SendMsg(x, format + "%s %d", args..., "xyz", 123);
}

void FOO(int x)
{
    SendMsg(x, "%s %d", "xyz", 123);
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302