Macro overloading - c++

Is it possible to define something like this:
#define FOO(x, y) BAR()
#define FOO(x, sth, y) BAR(sth)
so that this:
FOO("daf", sfdas);
FOO("fdsfs", something, 5);
is translated to this:
BAR();
BAR(something);
?
Edit:
Actually, BAR's are methods of my class. Sorry for not saying that before (didn't think it was relevant).
Answering DyP's question:
class Testy
{
public:
void TestFunction(std::string one, std::string two, std::string three)
{
std::cout << one << two << three;
}
void AnotherOne(std::string one)
{
std::cout << one;
}
void AnotherOne(void)
{
std::cout << "";
}
};
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N(_1, _2, _3, N, ...) N
#define PP_RSEQ_N() 3, 2, 1, 0
// macro for exactly 2 arguments
#define FOO_2(_1, _2) AnotherOne()
// macro for exactly 3 arguments
#define FOO_3(_1, _2, _3) AnotherOne(_2)
// macro selection by number of arguments
#define FOO_(N) FOO_##N
#define FOO_EVAL(N) FOO_(N)
#define TestFunction(...) FOO_EVAL(PP_NARG(__VA_ARGS__))(__VA_ARGS__)
And call:
Testy testy;
testy.TestFunction("one", "two", "three"); // line 9
Compiler output:
Warning 1 warning C4003: not enough actual parameters for macro 'PP_ARG_N' main.cpp 9
Warning 2 warning C4003: not enough actual parameters for macro 'FOO_' main.cpp 9
Error 3 error C2039: 'FOO_' : is not a member of 'Testy' main.cpp 9

Edit ------------------------------------------------look here----------------------------------------------------------------->
(Overloading macro on number of arguments)
// functions, or macros, ....
void bar(){}
void bar(int){}
#define EXPAND(X) X // for MSVC10 compatibility
// compute number of (variadic) macro arguments
// from http://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1
#define PP_NARG(...) EXPAND( PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) )
#define PP_NARG_(...) EXPAND( PP_ARG_N(__VA_ARGS__) )
#define PP_ARG_N(_1, _2, _3, N, ...) N
#define PP_RSEQ_N() 3, 2, 1, 0
// macro for exactly 2 arguments
#define FOO_2(_1, _2) bar()
// macro for exactly 3 arguments
#define FOO_3(_1, _2, _3) bar(_2)
// macro selection by number of arguments
#define FOO_(N) FOO_##N
#define FOO_EVAL(N) FOO_(N)
#define FOO(...) EXPAND( FOO_EVAL(EXPAND( PP_NARG(__VA_ARGS__) ))(__VA_ARGS__) )
int main()
{
int something = 42;
FOO("daf", sfdas);
FOO("fdsfs", something, 5);
}
Preprocessor output:
void bar(){}
void bar(int){}
int main()
{
int something = 42;
bar();
bar(something);
}
Edit2: Seems like VS2010 has some issues with __VA_ARGS__ and macro replacement.
UPDATE: It's ... a bug?? (also see this SO question):
#define MACRO2(PARAM0, PARAM1, ...) arg 0: >PARAM0< arg 1: >PARAM1< \
additional args: >__VA_ARGS__<
#define MACRO1(...) MACRO2(__VA_ARGS__, OTHERARG_0, OTHERARG_1)
MACRO1(ARG0, ARG1);
Preprocessor output:
arg 0: >ARG0, ARG1< arg 1: >OTHERARG_0< additional args: >OTHERARG_1<;
For a workaround, see the linked SO question. I've updated the original answer (code) above and tested it with MSVC10 -> works now.

Related

Wrap C++ function with default parameters in C

Say I have a function like this defined in a C++ header:
namespace foo {
void bar(int a, int b = 1);
}
and I would like to use this function in C code. One obvious solution would be to define two functions like this:
void foo_bar_1(int a)
{ foo::bar(a, 1); }
void foo_bar_2(int a, int b)
{ foo::bar(a, b); }
These can then easily be included in C code. However, this gets ugly for multiple default parameters, it would be nicer to have a single wrapper function. I thought about doing something like this:
#define _test_foo_numargs(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define test_foo(...) do { \
if (_test_foo_numargs(__VA_ARGS__) == 1) \
test_foo_1(__VA_ARGS__); \
else if (_test_foo_numargs(__VA_ARGS__) == 2) \
test_foo_2(__VA_ARGS__); \
} while (0)
But that doesn't work because both of the calls to test_foo_1 and test_foo_2 have to be valid in order for this to compile.
Is there a better way to do this?
I will provide my own solution here in case nobody has a better one and someone has the same problem in the future:
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
int _test_foo_1(int a)
{ return a; }
int _test_foo_2(int a, int b)
{ return a + b; }
int _test_foo_va(size_t num_args, ...)
{
va_list args;
va_start(args, num_args);
switch (num_args) {
case 1:
return _test_foo_1(va_arg(args, int));
case 2:
return _test_foo_2(va_arg(args, int), va_arg(args, int));
}
va_end(args);
}
#define _test_foo_numargs(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define test_foo(...) _test_foo_va(_test_foo_numargs(__VA_ARGS__), __VA_ARGS__)
int main()
{
printf("%d\n", test_foo(1));
printf("%d\n", test_foo(1, 2));
}
This is of course pretty unsafe because it will compile if too little or too many arguments are passed.
You might do the following:
#define TAKE_9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define COUNT(...) TAKE_9(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define CONCAT_(A, B) A ## B
#define CONCAT(A, B) CONCAT_(A, B)
#define SELECT(NAME, ...) CONCAT(NAME, COUNT(__VA_ARGS__))(__VA_ARGS__)
#define foo_bar(...) SELECT(foo_bar_, __VA_ARGS__)
Demo
COUNT can be upgraded to handle 0 arguments, if you compiler support it
#define COUNT(...) TAKE_9(__VA_ARGS__ __VA_OPT__(,) 8, 7, 6, 5, 4, 3, 2, 1, 0)
Demo
To avoid to have to write foo_bar_N, you might do:
// ...
#define FUNC_WITH_DEFAULT_ARG_2(func, DEFAULT, ...) TAKE_3(__VA_ARGS__ __VA_OPT__(,) \
func(__VA_ARGS__), \
func(__VA_ARGS__, TAKE_2 DEFAULT), \
func(TAKE_1 DEFAULT, TAKE_2 DEFAULT) )
#define FUNC_WITH_DEFAULT_ARG_3(func, DEFAULT, ...) TAKE_4(__VA_ARGS__ __VA_OPT__(,) \
func(__VA_ARGS__), \
func(__VA_ARGS__, TAKE_2 DEFAULT), \
func(__VA_ARGS__, TAKE_2 DEFAULT, TAKE_3 DEFAULT), \
func(TAKE_1 DEFAULT, TAKE_2 DEFAULT, TAKE_3 DEFAULT) )
// Choose on or other, error message for misuse might differ
// RequiredParameter is just a name for "better" error message when not enough parameter are given
#define foo_bar(...) FUNC_WITH_DEFAULT_ARG_2(foo_bar_impl, (RequiredParameter, 1), __VA_ARGS__)
#define foo_bar2(_1, ...) FUNC_WITH_DEFAULT_ARG_3(foo_bar_impl, (_1, 0), __VA_ARGS__)
void foo_bar_impl(int a, int b)
{ foo::bar(a, b); }
Demo

Can we nest #define and #if in C language?

I want to write the following code but it can't be compiled.
(core code piece)
void g();
#define MACRO(x) \
#if (x == 0) \
g(); \
#else \
h(); \
#endif
MACRO(0)
I think the reason may be that #if and #else must be placed in different lines but #define statement can only have one line. I don't know how can I fix the code. Can anyone help me? Thank you very much!
Update: This question occurs when I want to export a list of functions, each of which has one or more internal implementation. All the implementations may be of best perforamance depending on the parameters. See the code below.
void fun_1_algo_1(int x);
void fun_1_algo_2(int x);
void fun_2_algo_1(int x);
void fun_2_algo_2(int x);
// fun_1 and fun_2 both have two implementations.
// If x > 1, algo_1 is faster; otherwise algo_2 is faster
void fun_3_aogo_1(int x);
void fun_4_aogo_1(int x);
#define CHECK(x) .... //check if x is a legal number
#define Export(i) \
void fun_##i(int x) { \
CHECK(x); \
#if (i >= 1 && i <= 2) \
if (x > 1) fun_##i##_algo_1(x); \
else fun_##i##_algo_2(x); \
#else \
fun_##i##_algo_1(x); \
#endif \
}
Export(1)
Export(2)
Export(3)
Export(4)
In this example, I can't change #if to if because fun_3_algo_2(x) is undefined. The exported function will be used as a library.
No, you can't do that. You could approximate a solution using templates though.
// generic template to call h() for all values of x
template<uint32_t x>
struct func_chooser {
static inline void f()
{ h(); }
};
// specialise for the zero case (calls g())
template<>
struct func_chooser<0> {
static inline void f()
{ g(); }
};
// the macro just defers to the template
#define MACRO(x) \
func_chooser<x>::f();
Is there a reason you need the inner test to be a macro?
#define MACRO(x) ((x) == 0 ? g() : h())
will give you the behavior you want, and if you call it with a constant
MACRO(0)
the optimizer will constant fold and dead code eliminate it (so you'll end up with just a single call in the executable.) The only real drawback of this is that you can call it with a non-constant and it will compile to a test and two calls.
If you really need to do this in the preprocessor, you can use various token-pasting tricks to build macros that "evaluate" expressions by defining lots of macros covering every possible combination. BOOST_PP exists which may do a lot of this for you, or you can define a minimal set that meets your needs. In your case, something like:
#define IF1OR2ELSE_1(T, F) T
#define IF1OR2ELSE_2(T, F) T
#define IF1OR2ELSE_3(T, F) F
#define IF1OR2ELSE_4(T, F) F
#define IF1OR2ELSE_(I, T, F) IF1OR2ELSE_##I(T, F)
#define IF1OR2ELSE(I, T, F) IF1OR2ELSE_(I, T, F)
#define Export(i) \
void fun_##i(int x) { \
CHECK(x); \
IF1OR2ELSE(i, \
if (x > 1) fun_##i##_algo_1(x); \
else fun_##i##_algo_2(x); , \
fun_##i##_algo_1(x); \
) \
}
Export(1)
Export(2)
Export(3)
Export(4)
should do the trick. The basic idea is that the macro IF1OR2ELSE will expand to either its 2nd or 3rd argument depending on whether the first argument is 1 or 2 -- note that that is a token not a value, so something like 1U is not the same as 1.
You can generalize the above by building a bunch of helper macros that evaluate expressions (like BOOST_PP does)
#define IFELSE_true(T, F) T
#define IFELSE_false(T, F) F
#define IFELSE_(C, T, F) IFELSE_##C(T, F)
#define IFELSE(C, T, F) IFELSE_(C, T, F)
#define EQ_0_0 true
#define EQ_0_1 false
#define EQ_0_2 false
... many (100s?) of these for many different values
#define EQ_4_4 true
#define EQ_(A,B) EQ_##A##_##B
#define EQ(A,B) EQ(A, B)
#define OR_true_true true
#define OR_true_false true
#define OR_false_true true
#define OR_false_false false
#define OR_(A, B) OR_##A##_##B
#define OR(A, B) OR_(A, B)
now you can use
IFELSE(OR(EQ(i,1), EQ(i, 2)),
..code for i == 1 or i == 2 ,
..code for other cases
)
in your macros.
No, you cannot use #if (or any other preprocessor directive) inside a #define. Just use an ordinary if and let the compiler optimize out the unused code branch as needed.
#define MACRO(x) \
{ \
if (x == 0) \
g(); \
else \
h(); \
}
#endif
MACRO(0)

C++ or macro magic to generate method and forward arguments

I would like to create a magical macro, or anything, that would generate a something like this:
MAGICAL_MACRO(return_type, method_name, ...)
should work like this:
MAGICAL_MACRO(void, Foo, int a, int b)
->
virtual void Foo(int a, int b)
{
_obj->Foo(a, b);
}
Is this possible? I am afraid it is not.
Two questions: Are you open to a slightly different syntax for the arguments of MAGIC_MACRO? And can you use the Boost.Preprocessor header-only library?
If both answers are "yes", I have a solution for you:
#define MAGICAL_MACRO(Type, Name, ...) \
virtual Type Name(MAGICAL_GENERATE_PARAMETERS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))) {\
_obj->Name(MAGICAL_GENERATE_ARGUMENTS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))); \
}
#define MAGICAL_GENERATE_PARAMETERS(Args) \
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(MAGICAL_MAKE_PARAMETER, %%, Args))
#define MAGICAL_GENERATE_ARGUMENTS(Args) \
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(MAGICAL_MAKE_ARGUMENT, %%, Args))
#define MAGICAL_MAKE_PARAMETER(s, Unused, Arg) \
BOOST_PP_TUPLE_ELEM(2, 0, Arg) BOOST_PP_TUPLE_ELEM(2, 1, Arg)
#define MAGICAL_MAKE_ARGUMENT(s, Unused, Arg) \
BOOST_PP_TUPLE_ELEM(2, 1, Arg)
Usage looks like this:
MAGICAL_MACRO(void, Foo, (int, a), (int, b))
[Live example]
The %% used in the macro definitions is just my way of indicating "this value is not used." You could use pretty much anything else there (unless it contains a comma).
The above solution will work as long as the types involved are not spelled with a comma. If they are, introduce a type alias for them (typedef or using). Note that it is possible to get around this within the preprocessor magic itself, but it complicates already ugly code.
If you don't mind changing the syntax for the macro arguments, you could use following trick which abuses declaration syntax:
#define MAGICAL_MACRO(return_type, method_name, ...) \
virtual return_type method_name(__VA_ARGS__)
{ \
_obj->method_name(__VA_ARGS__); \
}
MAGICAL_MACRO(void, foo, int(a), int(b))
That will expand to:
virtual void foo(int(a), int(b))
{
_obj->foo(int(a), int(b));
}
Where void func(int(a), int(b)) is completely equivalent to void func(int a, int b).
The extra casts (or constructor calls depending on argument types) are ugly, but both GCC and Clang (with -O0) seem to ignore them not only for primitive types/PODs, but also for non-POD classes even if their copy constructors have side effects:
#include <iostream>
struct A
{
int x;
A(int value) : x(value) {}
A(const A &o)
{
x = o.x;
std::cout << "copy";
}
};
void func(A a)
{
std::cout << a.x << '\n';
}
void func1(A a)
{
func(a);
}
void func2(A a)
{
func(A(a));
}
int main()
{
func1(1); // prints `copy1`
func2(2); // prints `copy2`
}
The code below is working for what you've asked for with up to 1024 arguments and without using additional stuff like boost. It defines an EVAL(...) and also a MAP(m, first, ...) macro to do recursion and to use for each iteration the macro m with the next parameter first.
It is mostly copied from C Pre-Processor Magic. It is also great explained there. You can also download these helper macros like EVAL(...) at this git repository, there are also a lot of explanation in the actual code. It is variadic so it takes the number of arguments you want.
But I changed the FIRST and the SECOND macro as it uses a Gnu extension like it is in the source I've copied it from.
To split arguments like int a into int and a I used this answer from SO.
Your macro will be:
#define MAGICAL_MACRO(return_type, method_name, ...) \
virtual return_type method_name(__VA_ARGS__) \
{ \
return _obj->method_name(EVAL(MAP(TYPE_NAME, __VA_ARGS__))); \
}
Examples and limitations:
MAGICAL_MACRO(void, FOO, int a, double b, char c);
--> virtual void FOO(int a, double b, char c) { return _obj->FOO(a , b , c); };
MAGICAL_MACRO(int, FOO, int a, double b, char c);
--> virtual int FOO(int a, double b, char c) { return _obj->FOO(a , b , c); } ;
MAGICAL_MACRO(void, FOO, int* a, double* b, char* c);
--> virtual void* FOO(int* a, double* b, char* c) { return _obj->FOO(* a , * b , * c); };
/* maybe not what you want: pointer are dereferenced */
All the other macros needed, note that type splitting need to be defined per macro here:
/* Define all types here */
#define SPLIT_int int COMMA
#define SPLIT_char char COMMA
#define SPLIT_float float COMMA
#define SPLIT_double double COMMA
#define FIRST_(a, ...) a
#define SECOND_(a, b, ...) b
#define FIRST(...) FIRST_(__VA_ARGS__,)
#define SECOND(...) SECOND_(__VA_ARGS__,)
#define EMPTY()
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define DEFER3(m) m EMPTY EMPTY EMPTY()()()
#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()()()
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define CAT(a,b) a ## b
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define MAP(m, first, ...) \
m(first) \
IF_ELSE(HAS_ARGS(__VA_ARGS__))( \
COMMA DEFER2(_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _MAP() MAP
#define COMMA ,
#define CALL(A,B) A B
#define SPLIT(D) EVAL1(CAT(SPLIT_, D))
#define TYPE_NAME(D) CALL(SECOND,(SPLIT(D)))

Best way to deal with a trailing comma when using X macros in C++

What's the best way to deal with extra trailing commas when working with X macros? Specifically, I have the following setup in a file test01.cpp
struct Foo {
#define X(name,val) int name;
#include "test01.def"
#undef X
Foo() :
#define X(name,val) name(val),
#include "test01.def"
#undef X
{}
};
int main(){
Foo foo;
}
In test01.def, I have
X(foo,1)
X(bar,23)
This doesn't compile because of the error
test01.cpp: In constructor 'Foo::Foo()':
test01.cpp:10:5: error: expected identifier before '{' token
{}
Basically, there's a trailing comma after the last element in the member initializer list. Now, we can fix this by adding a dummy variable:
struct Foo {
private:
void * end;
public:
#define X(name,val) int name;
#include "test01.def"
#undef X
Foo() :
#define X(name,val) name(val),
#include "test01.def"
#undef X
end(nullptr)
{}
};
int main(){
Foo foo;
}
However, this is sort of ugly. As such, is there a better way to handle the trailing comma in the member initializer list?
Edit 1
Here's another option that's still kind of ugly:
struct Foo {
#define X(name,val) int name;
#include "test01.def"
#undef X
Foo() :
#define X(name,val) name(val),
#define XLAST(name,val) name(val)
#include "test01.def"
#undef XLAST
#undef X
{}
};
int main(){
Foo foo;
}
along with
#ifndef XLAST
#define XLAST X
#define CLEANUP
#endif
X(foo,1)
XLAST(bar,23)
#ifdef CLEANUP
#undef XLAST
#undef CLEANUP
#endif
Basically, we define the macro XLAST to take care of the final comma. If we use XLAST, we have to manually undefine it like X, but we do this automatically in the case that we don't define it explicitely.
Since you've tagged this C++14, the easiest way to solve this problem is to use brace-or-equal-initializers instead of the mem-initializers.
struct Foo {
#define X(name,val) int name = val;
#include "test01.def"
#undef X
// Foo() {} // uncomment if you do not want Foo to be an aggregate
};
If you want to stick with a preprocessor solution, you can use Boost.Preprocessor to do this. You'll need to change the format of your data member definitions so it forms a sequence.
#define FOO_MEMBERS ((int,i,10)) ((long,j,20))
I added the ability to specify arbitrary data types too.
First let's declare and initialize these data members
struct Foo
{
#define OP(s, data, elem) BOOST_PP_TUPLE_ELEM(3, 0, elem) \
BOOST_PP_TUPLE_ELEM(3, 1, elem) = \
BOOST_PP_TUPLE_ELEM(3, 2, elem);
BOOST_PP_SEQ_FOR_EACH(OP, , FOO_MEMBERS)
// expands to
// int i = 10; long j = 20;
#undef OP
Foo() = default; // default constructor
};
BOOST_PP_SEQ_FOR_EACH will expand the macro OP for each element in the sequence FOO_MEMBERS.
BOOST_PP_TUPLE_ELEM simply extracts a single element from its tuple argument.
Next, let's give Foo a constructor that takes arguments corresponding to each data member and initializes it.
#define OP(s, data, elem) (BOOST_PP_TUPLE_ELEM(3, 0, elem) BOOST_PP_TUPLE_ELEM(3, 1, elem))
Foo(
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(OP, , FOO_MEMBERS))
// expands to
// int i, long j
) :
#undef OP
#define OP(s, data, elem) (BOOST_PP_TUPLE_ELEM(3, 1, elem)(BOOST_PP_TUPLE_ELEM(3, 1, elem)))
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(OP, , FOO_MEMBERS))
// expands to
// i(i), j(j)
#undef OP
{}
We use BOOST_PP_SEQ_ENUM to generate a comma separated list from the result of the expansion of BOOST_PP_SEQ_FOR_EACH.
Live demo
If you declare end to be of std::nullptr_t type the compiler is likely to optimize it and remove it. And the intent is clear to the reader.
struct Foo {
private:
static std::nullptr_t end;
alternatively, you might declare char end[0]; (this won't use any space) but some compilers might reject that.
Of course, as Pratorian answered, you could use some X-macro friendly construct instead.
For anybody looking for a solution not involving a dependency on BOOST_PP, a preprocessor-based alternative, also useful for plain-old C, is to deal with a leading comma using the preprocessor, which is much easier than dealing with a trailing comma.
/// Indirection macro, so that macro expansion of parameters is done before token pasting.
#define REMOVE_FIRST(...) REMOVE_FIRST_SUB(__VA_ARGS__)
/// Paste all parameters but first.
#define REMOVE_FIRST_SUB(X, ...) __VA_ARGS__
#define FOO_DEF(X) \
X(foo,1) \
X(bar,23)
struct Foo {
#define X(name,val) int name;
FOO_DEF(X)
#undef X
Foo() :
#define X(name,val) ,name(val)
REMOVE_FIRST(FOO_DEF(X))
#undef X
{}
};
int main(){
Foo foo;
}
Testing:
$ gcc -E test.c
# 0 "test.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 0 "<command-line>" 2
# 1 "test.c"
# 11 "test.c"
struct Foo {
int foo; int bar;
Foo() :
foo(1) ,bar(23)
{}
};
int main(){
Foo foo;
}

Generate multiple macro calls according to the number of arguments

I'm trying to call this function several times in a repeditive fashion.
template<class T>
void METADATA_METHODS_IMPL(std::string& metadata, const T &value, const std::string &key)
{
metadata += boost::format("%1%:%2%") % key % value();
}
I have written the following macro:
#define METADATA_METHODS_IMPL_1(md, v1)\
METADATA_METHODS_IMPL(md, v1, #v1);
#define METADATA_METHODS_IMPL_2(md, v1, v2)\
METADATA_METHODS_IMPL_1(md, v1)\
METADATA_METHODS_IMPL_1(md, v2)
#define METADATA_METHODS_IMPL_3(md, v1, v2, v3)\
METADATA_METHODS_IMPL_2(md, v1, v2)\
METADATA_METHODS_IMPL_1(md, v3)
and so on ...
I need to call METADATA_METHODS_IMPL_N where N is a number of arguments in __VA_ARGS__
#define METADATA_METHODS(...)\
std::string METADATA_METHODS_IMPL_FUNC()\
{\
std::string metadata;\
BOOST_PP_OVERLOAD(METADATA_METHODS_IMPL_,__VA_ARGS__)(metadata, __VA_ARGS__)\
return metadata;\
}
The code above (with BOOST_PP_OVERLOAD) gives me unsuitable result:
class X
{
std::string F1();
std::string F2();
std::string F3();
METADATA_METHODS(F1, F2, F3);
};
This results in
std::string METADATA_METHODS_IMPL_FUNC()
{
std::string metadata;
METADATA_METHODS_IMPL(metadata, F1, F2, F3, "F1", "F2", "F3");
METADATA_METHODS_IMPL(metadata, , "");
METADATA_METHODS_IMPL(metadata, , "");
return metadata;
};
And I want something like this:
std::string METADATA_METHODS_IMPL_FUNC()
{
std::string metadata;
METADATA_METHODS_IMPL(metadata, F1, "F1");
METADATA_METHODS_IMPL(metadata, F2, "F2");
METADATA_METHODS_IMPL(metadata, F3, "F3");
return metadata;
};
Does anyone know how to achieve the desired result?
Can I use Boost.preprocessor library to automagically generate METADATA_METHODS_IMPL_K for some K in [1 .. 10] using METADATA_METHODS_IMPL_1
Using these macros we can cause the preprocessor to keep rescanning and allow for recursive macros.
#define EVAL(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
#define EVAL0(...) __VA_ARGS__
We can define some helper functions to build up concepts.
#define CAT(a, ...) PRIMITIVE_CAT(a,__VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define EMPTY()
#define EAT(...)
#define IDENT(...) __VA_ARGS__
#define DEFER(id) id EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
#define I_TRUE(t,f) t
#define I_FALSE(t,f) f
#define I_IS_DONE(a,b,...) b
#define TRUE_DONE() ~, I_TRUE
#define IS_DONE(b) OBSTRUCT(I_IS_DONE)(CAT(TRUE_,b)(),I_FALSE)
And build this Macro Mapping function that carries the first parameter to each.
#define MM() MM_CALL
#define MM_NEXT(Macro,md,a,...) \
IS_DONE(a)( \
EAT \
, \
OBSTRUCT(MM)() \
) \
(Macro,md,a,__VA_ARGS__)
#define MM_CALL(Macro,md,a,...) \
Macro(md,a) \
MM_NEXT(Macro,md,__VA_ARGS__)
#define MacroMap(Macro,md,...) EVAL(MM_CALL(Macro,md,__VA_ARGS__,DONE))
After defining the implementation related functions
#define METADATA_METHODS_IMPL_MACRO(md,a) \
METADATA_METHODS_IMPL(md, a, #a);
#define METADATA_METHODS(md,...) \
MacroMap(METADATA_METHODS_IMPL_MACRO,md,__VA_ARGS__) \
return md
This:
METADATA_METHODS(metadata, F1, F2, F3);
Results in this (after adding some formatting):
METADATA_METHODS_IMPL(metadata, F1, "F1");
METADATA_METHODS_IMPL(metadata, F2, "F2");
METADATA_METHODS_IMPL(metadata, F3, "F3");
return metadata;