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
I found a page that it is explained how identifier-token comparison can be implemented using c preprocessor directives. This could be done by some macros like this:
#define COMPARE_foo(x) x
#define COMPARE_bar(x) x
#define PRIMITIVE_COMPARE(x, y) IS_PAREN \
( \
COMPARE_ ## x ( COMPARE_ ## y) (()) \
)
PRIMITIVE_COMPARE(foo, bar) // expands to 0
PRIMITIVE_COMPARE(bar, bar) // expands to 1
Which IS_PAREN checks that it is completely expanded or not(which occurs just when two macros are different because of painting blue).
Now I am looking for a similar command in Boost Preprocessor. I want to have a list of accepted types of a macro and if the macro called with one of this type it expands to what it must otherwise it does not anything. My pseudo code is something like this:
#define ACCEPTED_TYPE (float)(int)(string)
#define Macro(x) // If one of accepted type do a otherwise do nothing
If boost preprocessor has not the exact solution what is your suggestion to make implementation easier.
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(~)
I have seen this question:
How to generate random variable names in C++ using macros?
with the following answer: https://stackoverflow.com/a/1675203/551045
And I've tried to implement it in clang.
Here is my declaration:
#define TRACE(stream) FuncTrace x#__COUNTER__ (llvm::errs(), "hallo", 1)
I tried all variations x##__COUNTER__; x ## __COUNTER__ and so on but none seem to work.
Could this be a clang bug? The clang help page says it has the __COUNTER__ macro.
In the end the macro I need something like this:
#define TRACE(stream) FuncTrace x#__COUNTER__ (stream, __FUNCTION__, __LINE__)
To concatenate two tokens into one you use the ## operator. The # operator is used to turn a token into a string.
x ## __COUNTER__ will just produce x__COUNTER__. You need to fully expand __COUNTER__ first. One possible method is add a few more indirections, e.g.
#define YTRACE(x, y) FuncTrace x##y (llvm::errs(), __FUNCTION__, __LINE__)
#define XTRACE(x, y) YTRACE(x, y)
#define TRACE(x) XTRACE(x, __COUNTER__)
I got stuck here...
#define CONCAT(a,b) BOOST_PP_STRINGIZE(BOOST_PP_CAT(a,b))#define CONCAT1(a,b,c) CONCAT(CONCAT(a,b),c) and so on. How i can to generate the CONCAT macro even if 20 arguments? May be i can to use BOOST_PP_SEQ_FOR_EACH but i don't understand how to do it?
It depends on you use-case.
This
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define SEQ (a)(b)(c)
BOOST_PP_STRINGIZE(BOOST_PP_SEQ_CAT(SEQ)) // "abc"
will concatenate the sequence and then stringize it. It is also possible to simply stringize each argument as "a" "b" "c" is equivalent to "abc".
#define MY_STRINGIZE(r, data, elem) BOOST_PP_STRINGIZE(elem)
BOOST_PP_SEQ_FOR_EACH(MY_STRINGIZE, _, SEQ)
As you are already using the Boost libraries, try BOOST_PP_SEQ_CAT (documentation). It takes a list of elements and simply concatenates them together, i.e. BOOST_PP_SEQ_CAT(a b c)
results in abc.