4

I'm currently working on a project where I need to simplfy an existing system. Wihtout going into the details the problem is that I get some function pointer (from type: void*) and I need to create a function from it (= create a function with signature). So my approach was to create the following variadic template function:

template <typename ReturnType, typename ... Params>
ReturnType(*GetFunction(void* func, Params ...)) (Params ...)
{
    return reinterpret_cast<ReturnType(*) (Params ...)> (func);
}

Now I need a way to create the needed functions:

#define DECLARE_PARAMS(...) __VA_ARGS__

#define Define_Function(returnType, fname, Params) returnType Gen_##fname (DECLARE_PARAMS Params)\
{\
    return  FUNCTION_DIRECTCALL(returnType, fname, (DECLARE_PARAMS Params));\
}

and here is the Problem. (I think) the Params don't expand the way they should expand. But I don't know why?

I tested the FUNCTION_DIRECTCALL in the DEFINE_FUNCTION macro with hardcoded values (simple put the defintion into the directcall) and it worked so there shouldn't be an error but I'm open for improvements

#define FUNCTION_DIRECTCALL(returnType, functionName, ...) \
GetFunction<returnType>(functionName, DECLARE_PARAMS __VA_ARGS__) ( DECLARE_PARAMS __VA_ARGS__)

If I try to define a function with the macro

Define_Function(void, ThatFunction, (int a_, int b_)); // void ThatFunction(int a, int b);

I get the following error: "Severity Code Description Project File Line Suppression State Error (active) incomplete type is not allowed [...]\main.cpp 34"

So my question is, what am I doing wrong? Is the problem really related to the Params in the DEFINE_FUNCTION macro or did I miss something?

I worked with macros but I wouldn't call myself an expert in this area. But the way I understand it is that (DECLARE_PARAMS Params) should expand the params to:

int a_, int b_

and after the scan I would expect the following code:

void Gen_ThatFunction(int a_, int b_)
{
    return GetFunction<void>(ThatFunction, a_, b_) (a_, b_);
}

Testing the Directcall macro: with the following code I tested the functionality of the directcall macro

Therefore I change the Define_Function macro:

#define Define_Function(returnType, fname, Params) returnType Gen_##fname (DECLARE_PARAMS Params)   \
{\
    int a = 2, b = 3;\
    return  FUNCTION_DIRECTCALL(void, ThatFunction, (a, b) );\
}

The definition of ThatFunction:

void ThatFunction(int a, int b)
{
    std::cout <<  a << " * " << b << " = " << b * a << std::endl;
}

output: "2 * 3 = 6"

All code compiled in VC++ 2015

MainCPP
  • 43
  • 4
  • You sure that shouldn't be `DECLARE_PARAMS(Params)`? – Claudiu Feb 16 '16 at 02:34
  • I don't see the point of `DECLARE_PARAMS` at all. Just take an ellipsis and use `__VA_ARGS__`. No need to forward it through another macro. – chris Feb 16 '16 at 02:55
  • @chris in this context the forwarding make no sense. But it's necessary for internal use (later). – MainCPP Feb 16 '16 at 03:02
  • Well in any case, you can't pass a comma-separated list as is as one argument. `Params` as a macro parameter isn't going to magically be capable of holding more than one argument. That's what the ellipsis is for. – chris Feb 16 '16 at 03:17
  • @Claudiu yes I'm sure that the way I do is right. Couldn't find the explanation will post it later (after I found it) – MainCPP Feb 16 '16 at 03:18
  • @chris no I expect the list is interpreted as an expression. If you are interested in a working example I can post the test case I have done to test the directcall. – MainCPP Feb 16 '16 at 03:22
  • Even if you define `DefineFunction` as nothing, `Define_Function(void, ThatFunction, int a_, int b_);` should be an error because you're passing four arguments to a macro with three parameters, the last of which is not an ellipsis. `FUNCTION_DIRECTCALL`, on the other hand, has an ellipsis. VS does have some non-standard behaviour that can cause a list such as `int a_, int b_` to be treated as a single argument in some cases, though. – chris Feb 16 '16 at 03:44

1 Answers1

0

The only way I know how to do what you're asking is really clunky.

#define DEFINE_FUNCTION(RET, NAME, TYPES, NAMES, BOTH) RET Gen_##NAME BOTH { return reinterpret_cast<RET(*)TYPES>(NAME) NAMES;  }

You use it like:

DEFINE_FUNCTION(void, ThatFunction, (int, int), (a_, b_), (int a_, int b_))

The return type and name of the void* (or function) are the first two parameters. Next is the list of the argument types enclosed by parenthesis, the argument names enclosed as well, and lastly the enclosed types AND names. Like I said, clunky.

This would generate the function:

void Gen_ThatFunction (int a_, int b_) { return reinterpret_cast<void(*)(int, int)>(ThatFunction) (a_, b_); }

You can then call the function as you wish:

Gen_ThatFunction(2, 3); //prints "2 * 3 = 6"

Of course, keep in mind this is Microsoft specific. Here, comma separated items enclosed by parenthesis are a single macro parameter. On any other compiler, this wouldn't work (that I'm aware of).

Weak to Enuma Elish
  • 4,622
  • 3
  • 24
  • 36
  • This was my first solution to this problem. But the client want a more "intuitive" solution. If you look at DEFINE_FUNCTION you see, that the macro looks exactly like a function declaration. And this is something I want to achive without developing a whole reflexion system. – MainCPP Feb 16 '16 at 14:50
  • @MainCPP Do the functions have overloads? If there's ever only one `Gen_ThatFunction`, you can make a reference to a variadic function template. Otherwise, I think you can only use a variadic function and just not have a visible set argument list. – Weak to Enuma Elish Feb 16 '16 at 16:29
  • yes their are overloads. Currently I have solved the Problem by just using a fixed amount of parameters macros (DECLARE_FUNCTION_ONE_PARAM) the Params will me seperated with an comma, so the problem is straight forward to solve. I will accept your answer because it's the solution for the described problem. – MainCPP Feb 17 '16 at 01:08