C/C++ expand multiple macros into one variadic macro - c++

Background
I am working on an existing codebase which uses a macro pattern to generate boilerplate methods similar to this:
START_MAP()
MAP_ENTRY(a)
MAP_ENTRY(b)
// .....
MAP_ENTRY(z)
END_MAP()
I am re-implementing the code that these macros generate, but I can not touch this pattern because that would require large refactors. I need to expand this pattern into a macro (which I define) which we will call NEW_IMPLEMENT which is a variadic macro that is called like so: NEW_IMPLEMENT(a, b, ..., z).
Problem
How can I redefine START_MAP, MAP_ENTRY, and END_MAP so that the pattern as it currently exists expands to NEW_IMPLEMENT(a, b, ..., z)?
What I have tried so far
#define NEW_IMPLEMENT(...) ...
#define START_MAP NEW_IMPLEMENT(
#define MAP_ENTRY(x) x,
#define END_MAP )
This throws a preprocessor error, however: error: unterminated argument list invoking macro "NEW_IMPLEMENT"

You can make the pattern expand to NEW_IMPLEMENT(stuff) text, but the resulting macro will not be expanded - C preprocessor does not rescan results from multiple macro expansions together.
You can "join" them, by wrapping everything in another macro call which will force another pass over all the results. And also you need to pass the paren as a token, not literally, so that you don't get unterminated call.
#define CALL(...) __VA_ARGS__
#define PAREN (
#define START_MAP() NEW_IMPLEMENT PAREN
#define END_MAP() )
#define MAP_ENTRY(a) a,
#define NEW_IMPLEMENT(...) "Hello: " #__VA_ARGS__
CALL(
START_MAP()
MAP_ENTRY(a)
MAP_ENTRY(b)
// .....
MAP_ENTRY(z)
END_MAP()
)
But overall, I do not understand. I would prefer to refactor the code with a simple sed 's/START_MAP()/NEW_IMPLEMENT(/; s/MAP_ENTRY(a)/a,/; s/END_MAP()/)/' for code readability and maintainability. I do not think "not touching ancient code" is a good enough reason for making the codebase more convoluted.

Related

the identifier __VA_ARGS__ can only appear in the replacement lists of variadic macros

I am attempting to create a macro to perform api calls. My current issue is the passing of parameters for the call. I get the following error message:
the identifier __VA_ARGS__ can only appear in the replacement lists of variadic macros
#define DO_CALL(api_name)(...) wow64hg::do_call(FNV(#api_name), __VA_ARGS__)
const auto status = DO_CALL(TerminateProcess)(process_handle, 0);
It technically may be possible to fix this by using operator loading, but I am confident there should be a way to keep it simple like this and get it to work.
Variadic macro syntax doesn't work like that; the ... has to represent additional arguments of the macro. A macro can't take multiple sets of arguments in separate sets of parentheses like an iterated function call.
I think you have to do the following:
#define DO_CALL(api_name, ...) wow64hg::do_call(FNV(#api_name), __VA_ARGS__)
const auto status = DO_CALL(TerminateProcess, process_handle, 0);

Macro that calls different function based on parameter

Hello all I was having trouble with macros so I thought I would practice and I was looking at the ## macro operator and thought I could use it for my problem I wan't to be able to call multiple functions based on the parameter for example if I have a macro like so:
#define macro(a) func##a();
int main()
{
.....
for(int i = 0;i< length;i++)
{
macro(i)
}
func1()
{
}
....
func31()
{
}
Anyone have an idea of how I can accomplish this??
You can only combine two preprocessor tokens. However, func isn't a preprocessor token. You need to jump through an extra hoop, calling some form of "concat" macro:
#define CONCAT(a, b) a ## b
#define macro(a) CONCAT(func,a)
Of course, the tokens produced by you macro won't be func1, ..., func31 (of course, they would also need to start with func0 if your logic were correct) but rather funci. The expansion of macros happens at the beginning of compilation while the execution of the for-loop happens at run-time (some optimizations may hoist it into compile-time but that won't affect the macros).
If you need to expand a sequence of integers in combination with a macro, you may want to have a look at the Boost preprocessor library, in particular at the BOOST_PP_REPEAT functionality.
If you just need to statically expand a sequence of integers to function calls, you might also consider looking at function template templatized on an integers: I would certainly consider using an approach using templates before trying to use the preprocessor library...

A previously defined constant, given as macro argument, is considered as string literal

Let's say I have defined a macro which does this
#define MY_MACRO(NAME) \
std::string get##NAME() const \
{ \
return doSomething(#NAME); \
}
Where doSomething method signature will be something like this
std::string doSomething(const std::string& parameter);
This works pretty well when the NAME macro parameter has no dashes in it.
For example :
#define MY_MACRO(thisIsA_test) // Works
But, when I have a dash in my string (this can happen) it won't work because dashes are not allowed in method names
#define MY_MACRO(thisIsA-test) // does NOT WORK
I have tried to work it around this way
#define thisIsAtest "thisIsA-test"
#define MY_MACRO(thisIsAtest)
Everything compiles just fine and I have the getthisIsAtest method generated but unfortunately the macro is not resolved and "thisIsAtest" is kept as string literal.
In other words the doSomething parameter string value will be "thisIsAtest" whereas I was expecting "thisIsA-test".
To expand the macro argument, just use an indirection macro.
#define stringize_literal( x ) # x
#define stringize_expanded( x ) stringize_literal( x )
Your use-case:
return doSomething( stringize_expanded( NAME ) );
Now the method will be named with name of the macro, and the function will be called with the contents of the macro. Somewhat questionable in terms of organization, but there you have it.
Why it works:
By default, macro arguments are expanded before being substituted. So if you pass thisIsAtest to parameter NAME, the macro expansion will replace NAME with "thisIsA-test". The pre-expansion step does not apply when you use a preprocessor operator # or ## though.
In your original code, one use of NAME is subject to ## and the other is subject to # so the macro definition of thisIsAtest never gets used. I just introduced a macro stringize_expanded which introduces an artificial use of NAME (via x) which is not subject to an operator.
This is the idiomatic way to use # and ##, since the expansion is desired more often than the literal macro name. You do happen to want the default behavior for ## in this case, but it could be considered a case of poor encapsulation (as the name of an interface is used to produce output), if you wanted to apply real programming principles to the problem.
There's nothing to work around.
As you have said yourself, dashes are not valid in function names.
So, do not use them.

Capture a name in C macro

The following iterator macro is given to me (cannot change)
#define ITERATE(MACRO) \
MACRO(v1) \
MACRO(v2) \
MACRO(v3) \
MACRO(v4)
The idea behind this is that I can now define my own one-argument macro and pass it into the iterator to expand for v1, v2, v3, v4. For example:
#define MYSTUFF(X) doSth(X);
ITERATE(MYSTUFF)
will expand to
doSth(v1); doSth(v2); doSth(v3); doSth(v4);
My current problem is that I want to invoke ITERATE within another macro which would like to pass an extra argument into MYSTUFF beyond one provided by the ITERATE.
To achieve that I was hoping that I could capture the extra parameter name with the following construct:
#define PARTIAL(T) FULL(UUU,T)
#define FULL(U,V) doSth(U,V)
#define START(UUU) ITERATE(PARTIAL)
START(bla)
I was hoping that when ITERATE(PARTIAL) is expanded to:
FULL(UUU,v1) FULL(UUU,v2) FULL(UUU,v3) FULL(UUU,v4)
I will actually capture the UUU parameter of START and it will be replaced by bla. Unfortunately that is not the case (at least in gcc).
Do you know if such name capturing can be achieved differently?
Or perhaps you have a different idea how to solve the problem of passing extra parameter into MACRO?
I may be permitted to change ITERATOR definition itself but only if it doesn't break any existing code already using it.
You can't do it this way. Your START() macro basically takes a single argument, which it then discards.
What you can do is define UUU where you need it, eg.
#define PARTIAL(T) FULL(UUU,T)
#define FULL(U,V) doSth(U,V)
#define START() ITERATE(PARTIAL)
// ...
#define UUU blah
START()
#undef UUU
Your problem, simplified, looks like this:
#define FOO UUU
#define START(UUU) FOO
START(5)
Here's what happens:
macro START is encountered in line START(5)
START is a function-like macro, so it becomes expanded with argument UUU=5):
stage 1 (argument expansion): macro arguments are macro-expanded
Nothing happens, 5 is not a macro.
Body: FOO
stage 2 (argument prescan): macro arguments are substituted into the macro body.
Nothing happens, UUU is not in the body.
Body: FOO
stage 3 (expansion): the body is macro-expanded again
FOO gets expanded into UUU, which is not a macro.
Body: UUU
I can't think of any clever way to expand FOO inside the body before the argument prescan happens. I don't think it's possible to do what you want directly.
Go with #Hasturkun's workaround and make UUU a macro, not a parameter.

How to single out the first parameter sent to a macro taking only a variadic parameter

I try to get at the first actual parameter sent to a variadic macro. This is what I tried, and which does not work in VS2010:
#define FIRST_ARG(N, ...) N
#define MY_MACRO(...) decltype(FIRST_ARG(__VA_ARGS__))
When I look at the preprocessor output I see that FIRST_ARG returns the entire argument list sent to MY_MACRO...
On the other hand when I try with:
FIRST_ARG(1,2,3)
it expands to 1 as intended.
This seems to be somehow the inverse of the problem solved by the infamous two level concat macros. I know that "macro parameters are fully expanded before inserted in the macro body" but this does not seem to help me here as I don't understand what this means in the context of ... and __VA_ARGS__
Obviously __VA_ARGS__ binds to N and is only evaluated later. I tried several ways with extra macro levels but it didn't help.
This is a bug in the Visual C++ preprocessor. The workaround listed there works. This:
#define FIRST_ARG_(N, ...) N
#define FIRST_ARG(args) FIRST_ARG_ args
#define MY_MACRO(...) decltype(FIRST_ARG((__VA_ARGS__)))
MY_MACRO(x, y, z)
expands to:
decltype(x)