I would like to write a macro which have one parameter and add this parameter to an enum and create a class with the same name. Is it possible in C++? If yes, than how?
To make it clearer here is an example what I want to do:
I call the macros like this:
REGISTER(A);
REGISTER(B);
REGISTER(C);
Or call the macros like this:
REGISTER(A, B, C);
And I want to get the preprocessor to generate code like this:
enum X { E_A, E_B, E_C };
class A {};
class B {};
class C {};
Something like this may help:
#define FE_1(WHAT, X) WHAT(X)
#define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
//... repeat as needed
#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) \
GET_MACRO(__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1)(action,__VA_ARGS__)
#define REGISTER_ENUM_VALUE(X) E_##X,
#define REGISTER_ENUM(...) enum X { FOR_EACH(REGISTER_ENUM_VALUE, __VA_ARGS__) }
#define REGISTER_CLASS(X) ; class X {}
#define REGISTER(...) REGISTER_ENUM(__VA_ARGS__) FOR_EACH(REGISTER_CLASS, __VA_ARGS__)
REGISTER(A, B, C);
Note that you can not get true variadic FOR_EACH, it will always be limited to a certain maximum amount of parameters for which you are planning and that you implemented manually. At least no-one found a way around it yet :)
Live example
Acknowledgment: Some code "stolen" from here.
Related
I am attempting to create a C++ DLL to export, and I need to export all functions of a class. So I came up with this idea to cut out the boilerplate:
#define CONCATENATE_WRAPPED(arg1, arg2) CONCATENATE_WRAPPED_1(arg1, arg2)
#define CONCATENATE_WRAPPED_1(arg1, arg2) CONCATENATE_WRAPPED_2(arg1, arg2)
#define CONCATENATE_WRAPPED_2(arg1, arg2) CONCATENATE_WRAPPED_3(arg1, arg2)
#define CONCATENATE_WRAPPED_3(arg1, arg2) CONCATENATE_WRAPPED_4(arg1, arg2)
#define CONCATENATE_WRAPPED_4(arg1, arg2) arg1##arg2
// Counts the number of pairs:
#define PAIR_SEQUENCER(_1, _1x, _2, _2x, _3, _3x, _4, _4x, N, ...) N
#define COUNT_PAIRS(...) PAIR_SEQUENCER(__VA_ARGS__, 4, x, 3, x, 2, x, 1, 0, 0, x)
// Internal for declaring arguments:
#define DECLARE_ARGUMENTS_0(...)
#define DECLARE_ARGUMENTS_1(typeName, varName, ...)\
typeName varName
#define DECLARE_ARGUMENTS_2(typeName, varName, ...)\
typeName varName,\
DECLARE_ARGUMENTS_1(__VA_ARGS__)
#define DECLARE_ARGUMENTS_3(typeName, varName, ...)\
typeName varName,\
DECLARE_ARGUMENTS_2(__VA_ARGS__)
// Internal for passing arguments:
#define PASS_ARGUMENTS_0(...)
#define PASS_ARGUMENTS_1(typeName, varName, ...)\
varName\
PASS_ARGUMENTS_0(__VA_ARGS__)
#define PASS_ARGUMENTS_2(typeName, varName, ...)\
varName, \
PASS_ARGUMENTS_1(__VA_ARGS__)
#define PASS_ARGUMENTS_3(typeName, varName, ...)\
varName, \
PASS_ARGUMENTS_2(__VA_ARGS__)
// Macro to call when declaring parameters and will adjust depending on the number of params, so that
// DECLARE_ARGUMENTS(int, a, float, b) expands to (int a, float b) for up to three pairs.
#define DECLARE_ARGUMENTS(...) ( CONCATENATE_WRAPPED(DECLARE_ARGUMENTS_, COUNT_PAIRS(__VA_ARGS__))(__VA_ARGS__) ))
// Macro to call when passing parameters and will adjust depending on the number of params, so that
// PASS_ARGUMENTS(int, a, float, b) expands to (a, b) for up to three pairs.
#define PASS_ARGUMENTS(...) ( CONCATENATE_WRAPPED(PASS_ARGUMENTS_, COUNT_PAIRS(__VA_ARGS__))(__VA_ARGS__) )
With all this context out of the way, this is what my main macro looks like:
#define IMPLEMENT_CONSTRUCTOR(typeName, functionName, ...) \
extern "C" __declspec(dllexport) typeName* __stdcall functionName DECLARE_ARGUMENTS(__VA_ARGS__) \
{ \
return new typeName PASS_ARGUMENTS(__VA_ARGS__); \
} \
typeName::typeName DECLARE_ARGUMENTS(__VA_ARGS__)
// the intention is so that
IMPLEMENT_CONSTRUCTOR(MacroTestObject, CreateMacroTestObjectWithTwoParams, int, TwoParamFirst, float, TwoParamSecond)
{ }
//expands to
extern "C" __declspec(dllexport) MacroTestObject* __stdcall CreateMacroTestObjectWithTwoParams(int TwoParamFirst, float TwoParamSecond)
{
return new MacroTestObject(TwoParamFirst, TwoParamSecond);
}
MacroTestObject::MacroTestObject(int TwoParamFirst, float TwoParamSecond)
{ }
But the problem seems to be that the C++ compiler starts compiling even before all the macros have expanded, which throws out compile-time errors like crazy, showing something like:
0><Project>\MacroTestObject.cpp(4,1): Error C2512 : 'MacroTestObject::MacroTestObject': no appropriate default constructor available
0><Project>\MacroTestObject.cpp(5,1): Error C2511 : 'MacroTestObject::MacroTestObject(void)': overloaded member function not found in 'MacroTestObject'
But when I use (Rider for Unreal Engine)'s "Substitute macro calls and all nested calls" function, the macro expands out just fine.
Can someone help me out with this, I don't know why this is happening and I can't seem to find any particular assistance online.
This DLL is meant to be used in Unity3D as a native plug-in and so as far as I know using C++/CLI is out of the question. I don't think COM interop is an option either because all the info I read about it implies that I need to create TLB files, and since Unity handles C# compilation, that seems out of the question too.
EDIT:
I think I kind of figured out why this is causing issues.
// Something like
COUNT_PAIRS(a, b, c, d, e, f)
// always expands to
0
// because __VA_ARGS__ is considered as a single argument
// and a recount is not triggered. I tried using CONCATENATE_WRAPPED
// in different places but unfortunately it has been no help.
Could someone help me out with this?
Edit 2:
Solved the problem, switched to Clang. Also, there's an extra bracket in DECLARE_ARGUMENTS macro.
So I think this version should now work as you would want.
I've found two problems:
The already mentioned additional ")" in DECLARE_ARGUMENT, that was an easy fix
The fact that MSVC seems to trat __VA_ARGS__ differently than gcc and clang, it doesn't expand the arguments into themselves but treats it one. That's why e.g. COUNT_PAIRS didn't work correctly. The fix is taken from this SO Question
I suggest playing around with it a bit in godbolt to see how it works ;)
Hope this solves your problem
EDIT: I also just saw here that Visual Studio has apparently updated their preprocessor, so depending on which version one is using it could be possible to avoid all the ugly EXPAND calls by using the compiler switch /Zc:preprocessor
Suppose I have a macro, a simple one that just calls a function foo for different type:
#define FOO(type) foo_##type();
In one go, let's say I want to call this thing for multiple different types. Concretely;
foo_int();
foo_float();
foo_point2d();
I want to generate above code with a macro called FOO2.
#define FOO2(args...) --fill--here
And just to be complete, FOO2(int, float, point2d) should expand into the above small code snippet. Is this possible with macros and how to do a different, separate thing for each argument in a variadic macro token pack?
I am sure a question like this is already asked. I searched for couple of other results, showing some sort of FOR_EACH macro implementation that were quite complicated and general. That's why I decided to ask for my specific use-case and started a new question.
Yes, it's possible, but requires multiple macros.
#define MAP1(m,t,...) m(t)
#define MAP2(m,t,...) m(t); MAP1(m,__VA_ARGS__)
#define MAP3(m,t,...) m(t); MAP2(m,__VA_ARGS__)
// ... add more as needed ...
#define MAP(n,...) MAP##n(__VA_ARGS__)
#define FOO(type) foo_##type()
#define FOON(n, ...) MAP(n, FOO, __VA_ARGS__)
FOON(3, int, float, double);
The above will generate:
foo_int(); foo_float(); foo_double();
If you don't want to specify the number as argument, add the following:
#define FOO1(...) FOON(1, __VA_ARGS__)
#define FOO2(...) FOON(2, __VA_ARGS__)
#define FOO3(...) FOON(3, __VA_ARGS__)
// ... add more as needed ...
And now you can just do:
FOO3(int, float, double);
With a bit more work you can even make the macro work with any function name:
#define MAP1(m,f,t,...) m(f,t)
#define MAP2(m,f,t,...) m(f,t); MAP1(m,f,__VA_ARGS__)
#define MAP3(m,f,t,...) m(f,t); MAP2(m,f,__VA_ARGS__)
// ...
#define MAP(n,...) MAP##n(__VA_ARGS__)
#define CALL(funcname, type) funcname##_##type()
#define CALLN(n, funcname, ...) MAP(n, CALL, funcname, __VA_ARGS__)
#define CALL1(...) CALLN(1, __VA_ARGS__)
#define CALL2(...) CALLN(2, __VA_ARGS__)
#define CALL3(...) CALLN(3, __VA_ARGS__)
// ...
CALL1(foo, int);
CALL2(bar, float, double);
CALL3(baz, whatever, you, want);
Result:
foo_int();
bar_float(); bar_double();
baz_whatever(); baz_you(); baz_want();
Trying to get this working in VS2013 (see Variadic macro trick and C++ preprocessor __VA_ARGS__ number of arguments).
It's not a duplicate afaik (versions posted elsewhere only work with GCC).
Any ideas what's wrong with this? I'm almost there...
#define _EXPAND(x) x
#define _VA_NARGS_IMPL(_1_, _2_, _3_, _4_, _5_, N, ...) N
#define _VA_NARGS_IMPL2(...) _EXPAND(_VA_NARGS_IMPL(__VA_ARGS__, 4, 3, 2, 1, 0))
#define _PUSH_X_FRONT(...) X, __VA_ARGS__
/*
Returns the number of arguments specified.
#ifndef _MSC_VER
#define VA_NARGS(...) _VA_NARGS_IMPL2(X,##__VA_ARGS__)
*/
#define VA_NARGS(...) _VA_NARGS_IMPL2(_PUSH_X_FRONT(__VA_ARGS__))
// testing is gewd
static_assert(VA_NARGS() == 0, "VA_NARGS() failed for 0 arguments");
static_assert(VA_NARGS(one, two, three, four) == 4, "VA_NARGS() failed for 4 arguments");
#define _VARARG_IMPL2(N, Macro, ...) Macro##N(__VA_ARGS__)
#define _VARARG_IMPL(N, Macro, ...) _VARARG_IMPL2(N, Macro, __VA_ARGS__)
// Helper function for variadic macros with per-argument processing.
#define VARARG(Macro, ...) _VARARG_IMPL(VA_NARGS(__VA_ARGS__), Macro, __VA_ARGS__)
#define _Quote1(x) #x
#define _Quote2(x, ...) #x, _Quote1(__VA_ARGS__)
#define _Quote3(x, ...) #x, _Quote2(__VA_ARGS__)
#define _Quote4(x, ...) #x, _Quote3(__VA_ARGS__)
// Treat each argument as a string literal, encompassing in quotes.
#define Quote(...) VARARG(_Quote, __VA_ARGS__)
Question:
constexpr char *a[] = { Quote(a, b) };
// WHY does the above produce {"a, b"} with msvc?
// The following produces {"a", "b"} as expected
constexpr char *a[] = { _Quote2(s, c) };
It is difficult to make a real variadic macro to work in VS2013. I had something done to expand a macro to be interpreted on it's own as a new macro. The key is to make multiple level macros. It is a lot to code but for given sample it will work.
#define InitialMacro (argument1, argument2) \
DetailedMacro(argument1, argument2, argument1##_description, argument2##_description)
#define DetailedMacro (argument1, argument2, argument3, argument4) \
L#argument1 \
L#argument2 \
L#argument3 \
L#argument4
The ideea presented here is to implement enough macros to cover all your requirement in the number of parameters nedeed. Also you can forward/update macro with aditional items on the way.
Basically first macro in this example append to the second and third transmitted parameters the suffix _description resulting in another macro that will get interpreted as a macro and it will be expanded in DetailedMacro.
You could also take a look at this: msvc variadic macro expansion
I would like to run macros on a list of class names to avoid copy/pasting errors and hassle.
Imagine, as a simple example, that every class in my SDK needs to call a static allocation method before it is used. So, every time I add a new class, I have to manually add the following line at initialization:
MyNewClass::allocate();
And I also need to do the same for initialization and destruction.
So, instead of doing this manually every time, I was wondering if there was a way to write a list of all my class names somewhere, then define a macro to call the corresponding methods for each class in the list. Something in the lines of:
#define ALLOCATE( TheClass ) TheClass ## ::allocate();
But instead of just passing TheClass as an argument, I'd like to pass a list of my classes. So by calling:
ALLOCATE_ALL( ClassA, ClassB, ClassC )
it would expand to:
ClassA::allocate();
ClassB::allocate();
ClassC::allocate();
Ultimately, I would like to be able to define a class list and have multiple macros iterate over it. Something in the lines of:
ALLOCATE_ALL( MyClassList )
INIT_ALL( MyClassList )
DESTROY_ALL( MyClassList )
I've already taken a look at variadic macros but, if I understand the concept correctly, you have to define as many macros as the final number of arguments; and that is simply not viable in my case.
Is this possible at all?
Thanks for any help and/or feedback.
If you are satisfied with having one list of classes, you can use the following trick:
#define MY_CLASSES X(ClassA) X(ClassB) X(ClassC)
Then you can do something like:
#define X(a) a::allocate();
MY_CLASSES
#undef X
To do something else, you can do:
#define X(a) a::init();
MY_CLASSES
#undef X
You could use a variadic function template :
#include <iostream>
// Thanks to Jarod42 for improving it !
template <class... TClasses>
void allocateAll() {
std::initializer_list<int>{(TClasses::allocate(), void(), 0)...};
}
struct C1 { static void allocate() { std::cout << "allocated C1\n"; } };
struct C2 { static void allocate() { std::cout << "allocated C2\n"; } };
struct C3 { static void allocate() { std::cout << "allocated C3\n"; } };
int main()
{
allocateAll<C1, C2, C3>();
return 0;
}
Outputs :
allocated C1
allocated C2
allocated C3
The functions are called in the same order that you pass their classes in.
You can also centralize the classes list :
// Use a template instead of a function so you can typedef it
template <class... TClasses>
struct ClassesList {
static void allocateAll() {
std::initializer_list<int>{(TClasses::allocate(), void(), 0)...};
}
// Add any other utilities here
private:
ClassesList();
};
// Declare your list
using MyClassesList = ClassesList<C1, C2, C3>;
int main(int, char**) {
// Just as before
MyClassesList::allocateAll();
}
To improve slightly the answer given by LindyLancer suggesting X-macros you could have a seperate file
// file my_classes.def
#ifndef MY_CLASS
#error MY_CLASS should be defined before including my_classes.def
MY_CLASS(ClassA)
MY_CLASS(ClassB)
/// etc...
#undef MY_CLASS
Then you would include that several times, e.g.
#define MY_CLASS(Classname) class Classname;
#include "my_classes.def"
and later, inside some initializer (or your main)
#define MY_CLASS(Classname) Classname::init();
#include "my_classes.def"
Using Boost.Preprocessor :
#include <boost/preprocessor/seq/for_each.hpp>
#define MyClassList \
(ClassA) \
(ClassB) \
(ClassC)
#define ALLOCATE_ALL( R, DATA, ELEM ) \
ELEM :: allocate();
#define INIT_ALL( R, DATA, ELEM ) \
ELEM :: init();
//...
BOOST_PP_SEQ_FOR_EACH( ALLOCATE_ALL, _, MyClassList )
BOOST_PP_SEQ_FOR_EACH( INIT_ALL, _, MyClassList )
You can define a generic macro that iterates, but the one time definition of it is ugly. This is because you do need one macro definition for each argument, up to the max number of nesting levels supported by your compiler (I believe the minimum is at least 63, but GCC is only limited by available memory). But since it is generic, you may find other uses of it.
For up to 5, a possible implementation is:
#define M_ITER(M, ...) \
M_ITER_(__VA_ARGS__, _5, _4, _3, _2, _1)(M, __VA_ARGS__)
#define M_ITER_(_1, _2, _3, _4, _5, X, ...) M_ITER ## X
#define M_ITER_1(M, X) M(X)
#define M_ITER_2(M, X, ...) M(X) M_ITER_1(M, __VA_ARGS__)
#define M_ITER_3(M, X, ...) M(X) M_ITER_2(M, __VA_ARGS__)
#define M_ITER_4(M, X, ...) M(X) M_ITER_3(M, __VA_ARGS__)
#define M_ITER_5(M, X, ...) M(X) M_ITER_4(M, __VA_ARGS__)
This is basically how BOOST_PP_SEQ_FOR_EACH is implemented.
And then, you could use it for your purpose like this:
#define ALLOCATE_ALL(...) M_ITER(ALLOCATE, __VA_ARGS__)
#define INIT_ALL(...) M_ITER(INIT, __VA_ARGS__)
#define DESTROY_ALL(...) M_ITER(DESTROY, __VA_ARGS__)
ALLOCATE_ALL(ClassA, ClassB, ClassC)
INIT_ALL(ClassA, ClassB, ClassC)
DESTROY_ALL(ClassA, ClassB, ClassC)
The accepted answer by Lindydancer is unsatisfactory to me because it relies on repeatedly redefining the X macro, which seems mysterious on use and could lead to collisions.
Instead, I prefer a variation that accepts the name of the macro as a parameter:
#define FOR_EACH_CLASS(macro) \
macro(ClassA) \
macro(ClassB) \
macro(ClassC)
This would be used liked like:
#define CALL_ALLOCATE(classname) classname::allocate();
FOR_EACH_CLASS(CALL_ALLOCATE)
#undef CALL_ALLOCATE /* optional undef */
There is another answer to a related question: Real-world use of X-Macros that gives more examples of the technique. (Note that, in that question, the accepted answer once again relies on redefining a macro with a particular name, whereas the one I linked accepts the macro name as a parameter.)
I'm writing a library that uses the preprocessor meta-programming Boost.Preprocessor. One macro looks kind of like this:
#define MY_MACRO(my_type) return some_function<my_type>()
Now, the problem is that I need to remove the return if my_type is void. I checked Boost.Preprocessor, but I didn't see anything that could help me. How do I accomplish this? Something like:
#define MY_MACRO(my_type) BOOST_PP_IF(\
TYPE_EQUALS(my_type,void),return,BOOST_PP_EMPTY()) some_function<my_type>()
Unfortunately, boost preprocessor doesn't have an easy way to compare two tokens. Of course for your case you may just need to use some simple detection. This should work on C99 preprocessors:
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1,
#define IS_VOID(x) CHECK(BOOST_PP_CAT(IS_VOID_, x))
#define IS_VOID_void PROBE(~)
However, this won't work for parenthesis, for varidiac data(such as types with commas in them), or pointers. So here are the ones that work and don't work:
IS_VOID(int) // 0
IS_VOID(void) // 1
IS_VOID((void)) // Compile error
IS_VOID(std::map<int, int>) // Compile error
IS_VOID(void*) // Returns 1, but should return 0
You could try to work around all these cases or you could use a more general comparison macro(like the one here):
#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x)
#define IS_PAREN_PROBE(...) PROBE(~)
#define IS_COMPARABLE(x) IS_PAREN( CAT(COMPARE_, x) (()) )
#define NOT_EQUAL(x, y) \
IIF(BITAND(IS_COMPARABLE(x))(IS_COMPARABLE(y)) ) \
( \
PRIMITIVE_COMPARE, \
1 EAT \
))(x, y)
#define EQUAL(x, y) COMPL(NOT_EQUAL(x, y))
#define COMPARE_void(x) x
#define IS_VOID(x) EQUAL(x, void)
Which could be updated to use boost preprocessor components. This should work for more cases, but still won't work with parenthesis(which may not be a problem).
Finally, this is just a comparison on the textual level, so if the user has typedefed void, it will incorrectly return false:
typedef void my_void;
IS_VOID(my_void) // Returns 0
If you are using the detection technique, you could allow the user to extend it for user-defined voids, like so:
#define IS_VOID(x) CHECK(BOOST_PP_CAT(IS_VOID_, x))
#define IS_VOID_void PROBE(~)
// User-defined void
#define IS_VOID_my_void PROBE(~)