2

I have this code:

std::string format(const char *fmt, ...);

#define DEBUG(HANDLER, LEVEL, ...) LOG##LEVEL(HANDLER, format(__VA_ARGS__))

It works when I use:

DEBUG(handler, DEBUG, "var is %d\n", 15);

but it doesn't work when I use:

DEBUG(handler, DEBUG, "test");

How can I check if there's only one argument or more than one?
I need to use C++98 solution only.

Azeem
  • 11,148
  • 4
  • 27
  • 40
greywolf82
  • 21,813
  • 18
  • 54
  • 108
  • You cannot. You need to pass that information either in your format or through some additional variable. – Duck Dodgers Feb 12 '19 at 10:22
  • @JoeyMallone I could modify the format function, but how? – greywolf82 Feb 12 '19 at 10:24
  • `__VA_ARGS__` was introduced C++11, so it can't be done in C++98 – Michael Veksler Feb 12 '19 at 10:24
  • @MichaelVeksler, I use `C++03` and I have `__VA_ARGS__`. `:)` I was about to test your answer with `__VA_OPTS__`, as I didn't know about that, but you deleted it. – Duck Dodgers Feb 12 '19 at 10:26
  • `__VA__OPT__` is C++20, no? https://en.wikipedia.org/wiki/Variadic_macro – Matthieu Brucher Feb 12 '19 at 10:27
  • 1
    @MatthieuBrucher you are correct, that's why I removed my answer. However, since `__VA_ARGS__` is available for OP's C++98 compiler (despite being C++11 feature), it might also have `__VA__OPT__` as part of the extension – Michael Veksler Feb 12 '19 at 10:31
  • @greywolf82, I didn't mean that. The information about how many parameters there are in a variadic macro can only be passed either **implicitly** in the format-string (I don't know how and I don't think you could access that information.) OR explicitly with an additional variable passed to the macro. I at least do NOT know of any other way. – Duck Dodgers Feb 12 '19 at 10:36
  • Possible duplicate of [C++ preprocessor \_\_VA\_ARGS\_\_ number of arguments](https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments) – Duck Dodgers Feb 12 '19 at 10:43

2 Answers2

1

Since __VA__ARGS__ is available on your otherwise C++98 compiler (despite being a C++11 feature), there is a chance it also has __VA_OPT__ as an extension:

You should use __VA_OPT__(something) (which is a C++20 feature) to make the comma appear only if there is at least one argument:

#define DEBUG(HANDLER, LEVEL, ...) LOG##LEVEL(HANDLER __VA_OPT__( format(__VA_ARGS__)))

or something similar that works for your case.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
1

So, I looked at your question and I looked at your code and I realized that this is probably a case of the infamous XY Problem.

Although you say, you want to count the number of arguments being passed to the macro, what you want to do is write debug messages which do not have any other parameters except a literal string which states a debug message as you show in the example.

DEBUG(handler, DEBUG, "test");

But that is of course possible. And to test it, I wrote the following bit of code.

std::string format(const char* fmt, ...) {
    char buffer[256];
    std::cout << __FUNCTION__ << std::endl;
    va_list argList;
    va_start(argList, fmt);
    vsprintf(buffer, fmt, argList);
    va_end(argList);
    return std::string(buffer);
}

#define TRC(...) {\
    std::cout << "MACRO!" << std::endl; \
    std::cout << format(__VA_ARGS__);\
}

int main()
{
    std::cout << "Hello World!" << std::endl;
    const char *t = "b";
    TRC("[%s] bla bla [%d]\n", t, 9);
    TRC("test");
    return 0;
}

which produces the output,

Hello World!
MACRO!
format
[b] bla bla [9]
MACRO!
format
test

Like I mentioned in the comments to your question earlier, I have C++03 compiler but this should work for C++98 also, I guess.

Question:

"How can I check if there's only one argument or more than one?"

The variadic macro itself has no problem whether you have one argument or more.

But if you really really still want to count the number of arguments passed in, I don't know of anyway in C++03 or earlier to do that.

Duck Dodgers
  • 3,409
  • 8
  • 29
  • 43