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'm trying to write some functions as macros, but I just can't figure it out how to do it.
#define PA0 (PORTA, PIN0_bm);
#define PA1 (PORTA, PIN1_bm);
...
#define PA7 (PORTA, PIN7_bm);
#define PD0 (PORTD, PIN0_bm);
#define PD1 (PORTD, PIN1_bm);
...
#define PD7 (PORTD, PIN7_bm);
then macro for function
#define pinMode(x) (x[0].DIRSET = x[1])
which I wanted to look like after preprocessor
pinMode(PA0) -> (PORTA.DIRSET = PIN0_bm)
After compiling (AVR-gcc) I'm getting invalid types 'int[int]' for array subscript error.
Is it possible to pass one argument to macro and get out two?
C++ macros end on the next newline, so the semicolons are being expanded, too. As originally suggested by Mooing Duck:
#JakobJug: Why not have the macros the other way around? #define pinmode(L,R) (L[0].DIRSET=R[1]) and then #define PA0 pinmode(PORTA,PIN0_bm)?
Except it needs a small correction, giving #define pinmode(L,R) (L.DIRSET=R). Then PA0 expands to pinmode(PORTA,PIN0_bm) and then (PORTA.DIRSET=PIN0_bm).
I understand the syntax of #define like,
#define Pi 3.14
So it's obvious that we can use Pi constant instead of 3.14 anywhere in code to make code more readable.
But I encountered a syntax like below.
Does it mean whenever I call the macro
doIT("hello world");
the code statements within {...} will be invoked ?
Does #define allow to give such syntax.?
What does the __FUNCTION__, __VA_ARGS__ mean ?
#define doIT(str, ...) \
{ \
if (pDoLog) pDoLog->LogMsg("[%s] Error: " str, LOG_WRONG, __FUNCTION__, ##__VA_ARGS__); \
printf("[%s] Error: " str "\n", __FUNCTION__, ##__VA_ARGS__); \
}
You don't "call" a macro, and its expansion doesn't get "invoked". The preprocessor just replaces the macro with its expansion, before the code gets compiled.
A macro defined with parentheses such as doIt(str) is a "function-like macro" which means it takes arguments which can be used in the expansion of the macro.
A function-like macro with ... in the argument list indicates it can accept a variable number of arguments. The special predefined symbol __VA_ARGS__ expands to the list of arguments passed to the ... placeholder.
__FUNCTION__ is a special predefined symbol that expands to the name of the current function being compiled, so wherever the macro gets expanded it will use the name of the enclosing function.
I have an function called ecall defined in external ASM file. This function takes different count of arguments and return different values.
This is how it looks like in my source code:
int ret = _function1("Hello", "world");
HANDLER h = _function2(123456);
char * ch = _function3("asdf", 789, h);
// ... and so on
These "functions" are actually macros generated with a simple python script. This auto-generated header file where all these macros are defined looks like:
extern "C" ????? ecall(int code, ...);
#define _function1(...) ecall(0x123, __VA_ARGS__)
#define _function2(...) ecall(0x234, __VA_ARGS__)
#define _function3(...) ecall(0x345, __VA_ARGS__)
#define _function4(...) ecall(0xABC, __VA_ARGS__)
// ... and around 500 more definitions with a different code value
However, I am stuck on the declaration of the ecall (I've marked as "?????"). I need to somehow specify return values, but in fact this function returns pretty much everything (depending on int code value) -- booleans, integers, pointers, etc.
Is there a way how to do this? I am compiling on MSVC10.
Thanks.
Either create your own variant type (a union with each type included), or as I would more strongly suggest, create different functions that each return only one specific type.
Shouldn't this:
#define MOGSH_CONCAT (x,y) x##y
#define MOGSH_DOUBLE (a,b) MOGSH_CONCAT(a,b)
#define MOGSH_DEFINEPROC (p) MOGSH_DOUBLE(_gt,p) options_dialog::p;
MOGSH_DEFINEPROC(AssignMainForm);
happily expand to:
_gtAssignMainForm options_dialog::AssignMainForm;
Given that _gt is not defined, _gtAssignMainForm is:
typedef void (__stdcall *_gtAssignMainForm)();
and options_dialog is just a class where AssignMainForm is a static member.
Instead, in MSVC9, I get the error:
'a' : undeclared identifier
on the line containing
MOGSH_DEFINEPROC(AssignMainForm);
In the definition of a function-like macro there can be no whitespace between the macro name and the ( beginning the parameter list.
#define MOGSH_CONCAT(x,y) x##y
// ^ no whitespace allowed here
As you have it now (with whitespace), MOGSH_CONCAT is an object-like macro with a replacement list of (x,y) x##y, which is why you are getting such strange results.