c++ variadic macro: how to retrieve arguments values - c++

In the class there are a lot of methods with similar implementation, only method's name and argument-list different:
void function1 (int a, bool b)
{
mMember->function1(a, b);
}
void function2 (double a, string b)
{
mMember->function2(a, b);
}
It is required to replace all them with variadic macro.
Something like this
#define MYMACRO(funcname, ...) void funcname (__VA_ARGS__) { mMember->funcname (__VA_ARGS__)}
but it is generated into such call
mMember->function1(int a, bool b)
And of course gives compilation errors.
How can parameters' values be got inside macro, so that to pass them into mMember->funcname without types?
mMember->function1(a, b)

How can parameters' values be got inside macro, so that to pass them into mMember->funcname without types?
It is not possible. The typical solution is to pass types and variables in separate arguments and have two separate chains of expansions. This will not work without typedef for function types or array types.
// Macro overloading on number of arguments left for the reader.
// This is a static example for 4 arguments.
#define MYMACRO_ARGS(a, b, c, d) a b, c d
#define MYMACRO_PARAM(a, b, c, d) b, d
#define MYMACRO(funcname, ...) \
void funcname(MYMACRO_ARGS(__VA_ARGS__)) { \
mMember->funcname(MYMACRO_PARAM(__VA_ARGS__)); \
}
MYMACRO(function2, double, a, string, b)
Overall, I recommend not doing it. Hiding your code behind a macro will make your code harder to read and maintain. Strongly consider just writing the stuff out, instead of making it very hard for linters, code analyzers, and programmers and confusing yourself with unreadable error messages from the compiler.

Related

How to prefix __VA_ARGS__ elements in a macro

Is it possible to prefix each element of variadic parameters with something else?
#define INPUTS(...) ???
Function(INPUTS(a, b, c))
should become
Function(IN a, IN b, IN c)
Take a look at Boost.Preprocessor.
While daunting, it can be used to do all kinds of weird things, like exactly this:
#include <boost/preprocessor.hpp>
#define MAKE_IN_ARG(r,_,arg) (IN arg)
#define ARGS(...) \
BOOST_PP_SEQ_TO_TUPLE( \
BOOST_PP_SEQ_FOR_EACH(MAKE_IN_ARG,, \
BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))
void f ARGS( int a, float b, char c )
{
//...
}
Produces:
void f (IN int a, IN float b, IN char c )
{
}
That said...
You are making a mistake. Don’t do this. Just type out the IN in front of every input argument when you write the function header. Your life will be significantly easier.

How to add a statement at the end of a line containing a macro in C/C++?

To reduce the number of lines to be written, i am using macros in the following way:
#define FUNC(a, b) func(a, b, threadId, sizeof(a)); \
do something 1; \
do something 2;
This works well, as i just need to use the macro (with 2 parameters) that encodes the function call (with 4 parameters) and 2 or more other statements.
Problem arises when this function call is a parameter to another function.
For example, suppose i need the following code:
func1(par1, func(a, b, c, d));
do something 1;
do something 2;
Is there a way to achieve this using macros, or any other alternatives?
i.e. I am expecting something like:
func1(par1, FUNC(a, b)); //This statement(using macros) should transform into the above code after the preprocessing step.
I'm not sure what you are actually trying to achieve, but replacing this:
#define FUNC(a, b) func(a, b, threadId, sizeof(a)); \
do something 1; \
do something 2;
by this (assuming the type of the a and b parameters is int):
int FUNC(int a, int b)
{
int returnvalue = func(a,b,threadId, sizeof(a));
do something 1;
do something 2;
return returnvalue;
}
should do the job.
You could try to isolate the code with brackets { }. But your idea is not one I would recommend, as the code becomes very hard to understand and debug.
#define FUNC(a, b) { func(a, b, threadId, sizeof(a)); \
do something 1; \
do something 2; }
But if you try to send this as a parameter to another function it still won't work because you are not returning anything to be uses as a parameter ( no adress, no value)

What are options to get multiple variable lists in a variadic macro?

I have been trying to use variadic macros to reduce redundant code in some SFINAE patterns I am using. Specifically, I would like to generate function definitions using variadic macros. (This question is not about SFINAE). For my application, I would like write a wrapper function that calls an existing member function. The actual application requires that I produce a templated struct with SFINAE specialization so there is some repetitive stuff that would be great to just have a macro take care of generating the struct and function. OK that is the motivation.
The following example dispenses with all of the SFINAE stuff and simply defines a struct with three static functions (f0, f1, f2) with different parameter lists, and tries to call these functions through global macro generated function. Why would you want to do this?? You wouldn't. But this is just to illustrate the problem that I was having for the SFINAE application.
#include<iostream>
struct Foo
{
static void f0()
{
std::cout<<"f0() called"<<std::endl;
}
static void f1(int a)
{
std::cout<<"f1("<<a<<") called"<<std::endl;
}
static double f2(int a, double b)
{
std::cout<<"f2("<<a<<","<<b<<") called"<<std::endl;
return a*b;
}
};
#define VA_LIST(...) __VA_ARGS__
#define FUNCTION_WRAPPER(NAME,RTYPE,PARAMS,ARGS)\
RTYPE NAME(PARAMS)\
{\
return Foo::NAME(ARGS);\
}
FUNCTION_WRAPPER(f0,void,VA_LIST(),VA_LIST())
FUNCTION_WRAPPER(f1,void,VA_LIST(int a),VA_LIST(a))
FUNCTION_WRAPPER(f2,double,VA_LIST(int a, double b), VA_LIST(a, b))
int main()
{
f0();
f1(1);
f2(1,4.2);
return 0;
}
OK. So the VA_LIST(...) __VA_ARGS__ enables the creation of a single variable list. The call:
FUNCTION_WRAPPER(f2,double,VA_LIST(int a, double b), VA_LIST(a, b))
utilizes to variable lists as argument 3 and 3. Note that the Parameter list and the Argument list have to be consistent with each other (i.e. variables passed in the Argument list better be declared in the Parameter list.
This seems to work for this example, although there are issues if we were to try to add an fixed argument to beginning of the call (e.g. Foo::NAME(fixedArg, ARGS) ). It appears that the ##__VA_ARGS trick to swallow the comma if the variable list is empty doesn't work with this approach.
So the questions I have is:
While this approach seems to work properly on both gcc and clang, I can't find any similar examples that uses multiple variable lists in this manner...which makes me a little nervous. Is this a valid approach?
So what is actually happening in this approach? How is the FUNCTION_WRAPPER macro able to handle two variable lists? Are the PARAMS and ARGS macro arguments simply being expanded in the body of the macro, or is there something more complex happening here?
Is there a way to use the ## trick to swallow preceding commas? Placing the ## preceding the PARAMS and ARGS values in the macro body result in a compilation error, as does placing the ## in the VA_LIST.
Sample code for this last case is:
#define VA_LIST2(...) __VA_ARGS__
#define FUNCTION_WRAPPER2(NAME,RTYPE,PARAMS,ARGS)\
RTYPE NAME##_2(PARAMS)\
{\
return Foo::NAME(1,ARGS);\
}
FUNCTION_WRAPPER2(f2,double,VA_LIST2(double b), VA_LIST2(b))
The error for the insertion of ## into the FUNCTION_WRAPPER body is
error: pasting "," and "VA_LIST" does not give a valid preprocessing token
return Foo::NAME(1,##ARGS);\
The compilation error for the insertion of ## into the VA_LIST macro body is:
error: '##' cannot appear at either end of a macro expansion
#define VA_LIST2(...) ##__VA_ARGS__
^
How is the FUNCTION_WRAPPER macro able to handle two variable lists?
C preprocessor first recognizes arguments of a macro, then expands the arguments, then replaces the body of the macro with the expansion of arguments.
Because macro arguments are first "recognized" before expanded, macro expansion inside arguments resulting in a comma doesn't change the count of arguments.
Is there a way to use the ## trick to swallow preceding commas?
Be aware that it is still a GNU extension. Standard alternative to GCC's ##__VA_ARGS__ trick?
Yes, just make them to VA_ARGS so you can ## them.
#define VA_LIST2(...) __VA_ARGS__
#define ADD_ONE(...) 1,##__VA_ARGS__
#define FUNCTION_WRAPPER2(NAME,RTYPE,PARAMS,ARGS)\
RTYPE NAME##_2(PARAMS)\
{\
return Foo::NAME(ADD_ONE(ARGS));\
}
FUNCTION_WRAPPER2(f2,double,VA_LIST2(), VA_LIST2())
FUNCTION_WRAPPER2(f2,double,VA_LIST2(double b), VA_LIST2(b))
Is this a valid approach?
Sure, it's great. I would drop VA_LIST from the call. Lists in preprocessor are just done with (...). Then, just apply VA_LIST on the (...) argument.
#define VA_LIST(...) __VA_ARGS__
#define FUNCTION_WRAPPER(NAME,RTYPE,PARAMS,ARGS)\
RTYPE NAME(VA_LIST PARAMS) \
{ \
return Foo::NAME(VA_LIST ARGS); \
}
FUNCTION_WRAPPER(f0,void,(),())
FUNCTION_WRAPPER(f1,void,(int a),(a))
FUNCTION_WRAPPER(f2,double,(int a, double b), (a, b))
#define ADD_ONE(...) 1,##__VA_ARGS__
#define FUNCTION_WRAPPER2(NAME,RTYPE,PARAMS,ARGS)\
RTYPE NAME##_2(VA_LIST PARAMS) \
{ \
return Foo::NAME(ADD_ONE ARGS); \
}
FUNCTION_WRAPPER2(f2,double,(), ())
FUNCTION_WRAPPER2(f2,double,(double b), (b))
Anyway, double b .... b you are repeating yourself, however it is very clean and very flexible. You might want to see How to use variadic macro arguments in both a function definition and a function call? , c++ variadic macro: how to retrieve arguments values where I'm passing types and variable names as separate tokens and splitting them later differently depending on if it's function parameter list or call parameters.

Dropping the last comma in a macro

I am using the X macro pattern to keep a bunch of arrays/items in sync, and I want to create an argument list from it, however I can't work out a way to get a well formed list. Here's what I mean:
#define MY_DATA \
X(var_one, e_one, 1) \
X(var_two, e_two, 2) \
X(var_three, e_three, 3) \
#define X(a,b,c) b,
enum MyNumbers {
MY_DATA
};
#undef X
#define X(a,b,c) c,
int MyValues[] = {
MY_DATA
};
#undef X
void my_func(int a, int b, int c) {} // example do-nothing proc
void main(void)
{
int var_one = MyValues[e_one];
int var_two = MyValues[e_two];
int var_three = MyValues[e_three];
#define X(a,b,c) a,
my_func(MY_DATA); // this fails because of the trailing comma
#undef X
}
Macros are not really my forte, so I can't think of a way of getting rid of the final comma in the function call. Can anyone think of a way to stop it?
Look at the Boost Preprocessor library for “preprocessor metaprogramming tools including repetition and recursion.”
Even if you don't use their complete package, the chapter I linked to explains some techniques, specifically including iteration to build data structures and statements.
Here's an idea: write
my_func(MY_DATA 0);
and declare my_func to take an extra (ignored) argument.
void my_func(int a, int b, int c, int)
I use a variant of this pattern frequently. However, it is normally used to define mappings between data. Along the lines of this:
MESSAGE(10, "Some error message"),
MESSAGE(11, "Som other error message"),
What des not make sense in your approach is that typically these constructs are used for large numbers of entries (100s, 1000s). You normally do not want that many arguments to a function.
If you really want to follow the approach, you could add another MACRO
#define MY_DATA \
X(var_one, e_one, 1) COMMA \
X(var_two, e_two, 2) COMMA \
X(var_three, e_three, 3) \
and define comma as needed when you define X. (Or you could just put the comma in directly).
Here is an option:
void my_func(int a, int b, int c, int dummy) {}
// ...
my_func(MY_DATA 0);
If you can't change my_func then make a thunk (i.e. an intermediate function that calls my_func)
A second option would be to include the comma in the MY_DATA macro instead of in X:
#define MY_DATA \
X(var_one, e_one, 1), \
X(var_two, e_two, 2), \
X(var_three, e_three, 3)

Passing "int" as argument in macro

This has been bugging me for some time, I came across this while solving some objective type questions in C.
#define SWAP(a,b,c) c t;t=a;a=b;b=t;
int main() {
int x=10,y=20;
SWAP(x,y,int);
}
The code gives the correct answer:
Working code
In C are we supposed to pass just a data type as an argument.This supposedly works here but I want to know how.Also two more questions related to this:
If I want to swap using pointers, will it work
Will this work if SWAP is defined as a function instead of a macro.
Macros are pre-processed before compilation and you can virtually write anything in macros that would be replaced. In function arguments, you can not pass data types as arguments.
Side note:
#define SWAP(a,b,c) do { c t;t=a;a=b;b=t; } while(0)
is a safer macro implementation than the one mentioned by you. Moreover name t is quite common. If either of the argument name is t, this won't work as expected, so better choose some rare name. Capital letters are usually preferred in macro definition.
for ex: #define SWAP(a,b,c) do { c MACRO_TEMP_;MACRO_TEMP_=a;a=b;b=MACRO_TEMP_; } while(0)
SWAP(x,y,int); Becomes c t;t=a;a=b;b=t; where all occurances of c are replaced with int, a with x and b with y. Resulting in: ìnt t; t = x; x = y; y = t;
To understand the macros better, you can see the pre-processed output of your code. Output on my computer:
$ cat q26727935.c
#define SWAP(a,b,c) c t;t=a;a=b;b=t;
int main() {
int x=10,y=20;
SWAP(x,y,int);
}
$ gcc -E q26727935.c
# 1 "q26727935.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "q26727935.c"
int main() {
int x=10,y=20;
int t;t=x;x=y;y=t;;
}
$
Macro is replacement at pre-processor stage, so swap will work even with pointers, although this is superfluous.
In function you can not pass data type as arguments, so it won't work.
Yes.
No.
First of all, you have to know that when you are using macros, the argument will be replaced as they are. So, if you call SWAP(a, b, int*), it will be replace with
int* t;t=a;a=b;b=t;
and then the code will be compiled.
But when you're using functions, that won't happen and you're unable to pass data type as an argument to a function.