0

I want to remove the comma characters inside __VA_ARGS__.
I have found a FOR_EACH implementation, which kind of solves it, but gives cluttered error messages when there is a mistake.

My problem has the following properties:

OUTER(INNER(A), INNER(B))

I want to keep the comma in the line above so that the auto-formatter can do its job.
But I want to get rid of it inside the macro, so my idea was this: embed the comma inside a

static_assert("" COMMA_HERE "");

like this:

#define OP static_assert(""
#define CP "");

#define OUTER(...) OP __VA_ARGS__ CP
#define INNER(...) CP __VA_ARGS__ OP

This also works.

Now I want to pass __VA_ARGS__ to another macro.
This is where I am stuck. If I change OUTER to, for example:

#define OUTER(...) OP ID(__VA_ARGS__) CP

then the single brackets of OP and CP mess with the result.
How can this be corrected?

12
  • 5
    Show an example of code you want to start with (the actual code that will appear in the source file) and the code you want to result from preprocessing. Commented Nov 28 at 12:14
  • which kind of solves it, but gives cluttered error messages when there is a mistake. so use it, it is the solution. How can this be corrected? with a for each macro. You can get the error message dpwn to... I think like 4 "in expansion of" messages, still a lot. Preprocessor will just give cluttered error messages. Also, if this is a message, maybe just #__VA_ARGS__. Commented Nov 28 at 13:00
  • @EricPostpischil I want to generate nested class hierarchies. Minimal example: class Root{ class Child1{}; class Child2{};} Children may have more children. OUTER(Root, INNER(Child1), INNER(Child2)). Clang-format would be able to properly indent it only with the comma. Commented Nov 28 at 13:13
  • 1
    Fwiw: If you use macros to do this in C++, your code will most probably be rejected in code review. Commented Nov 28 at 14:14
  • 2
    IMO OP should describe feature he want to achieve instead asking how to fix his solution to some problem. Commented Nov 28 at 14:24

1 Answer 1

3

Assuming you have at least one necessary parameter and zero or more optional parameters after it - you can use a ##__VA_ARGS__ variation of standard __VA_ARGS__:

#define OUTER(necessary, ...) outer((necessary), ##__VA_ARGS__)

OUTER(123);
// Would become: outer((123));
OUTER(123, 456);
// Would become: outer((123), 456);

The syntax of ##__VA_ARGS__ was introduced by gcc in a very distant past, and is copied by almost all other compilers. But it is still not part of language standard. You can lookup the documentation for it here: https://gcc.gnu.org/onlinedocs/gcc-3.2/cpp/Variadic-Macros.html

As an option, you can try __VA_OPT__(,) macro, it was added into recent C++ standard, and would transform into a comma if __VA_ARGS__ is not empty. If __VA_ARGS__ is empty, the __VA_OPT__(,) would become an empty string. But this macro is fairly recent and could be unsupported if you are using an older language standard.

Here is gcc's documentation describing the __VA_OPT__() and its relationship with ##__VA_ARGS__: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

If you are using a different compiler, you most likely still can use these two approaches to deal with comma before the list of optional parameters, since majority of compilers follow gcc example. Or lookup the "variadic macros" in the documentation for your specific compiler and language standard.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.