Your warning is caused by the ternary operators having multiple types in their sub-expressions, i.e.:-
cond ? expression of type 1 : expression of type 2
the two expressions need to evaluate to the same type, which doesn't really help you much.
To solve your problem, I can think of two solutions, both of which are a bit nasty.
Use VARARGS / variadic functions
Define your function using the '...' parameter and store the parameters somewhere using the given macros and define the target function as accepting a va_list. You do lose every bit of type safety, compiler checking and require extra meta data for the functions as well as re-writing the target function to use a va_list.
Drop to assembler and hack the stack
Told you it was nasty. Given a function to call:-
void FuncToCall (type1 arg1, type2 arg2);
create a function:-
void *FuncToCallDelayed (void (*fn) (type1 arg1, type2 arg2), type1 arg1, type2 arg2);
which copies the parameters on the stack to a dynamically allocated block of memory which is returned. Then, when you want to call the function:-
void CallDelayedFunction (void *params);
with the pointer the call to FuncToCallDelayed returned. This then pushes the parameters onto the stack, and calls the function. The parameters and the function pointer are in the params parameter.
This method does tie you to a specific processor type but at least keeps some form of type checking on the parameter list.
Update
Here's a version of Method 2, built for Visual Studio 2012, IA32, running on Win7:-
#include <iostream>
using namespace std;
__declspec (naked) void *CreateDelayedFunction ()
{
__asm
{
mov esi,ebp
mov eax,[esi]
sub eax,esi
add eax,4
push eax
call malloc
pop ecx
or eax,eax
jz error
mov edi,eax
sub ecx,4
mov [edi],ecx
add edi,4
add esi,8
rep movsb
error:
ret
}
}
void CallDelayedFunction (void *params)
{
__asm
{
mov esi,params
lodsd
sub esp,eax
mov edi,esp
shr eax,2
mov ecx,eax
lodsd
rep movsd
call eax
mov esi,params
lodsd
add esp,eax
}
}
void __cdecl TestFunction1 (int a, long long b, char *c)
{
cout << "Test Function1: a = " << a << ", b = " << b << ", c = '" << c << "'" << endl;
}
void __cdecl TestFunction2 (char *a, float b)
{
cout << "Test Function2: a = '" << a << "', b = " << b << endl;
}
#pragma optimize ("", off)
void *__cdecl TestFunction1Delayed (void (*fn) (int, long long, char *), int a, long long b, char *c)
{
return CreateDelayedFunction ();
}
void *__cdecl TestFunction2Delayed (void (*fn) (char *, float), char *a, float b)
{
return CreateDelayedFunction ();
}
#pragma optimize ("", on)
int main ()
{
cout << "Calling delayed function1" << endl;
void *params1 = TestFunction1Delayed (TestFunction1, 1, 2, "Hello");
cout << "Calling delayed function2" << endl;
void *params2 = TestFunction2Delayed (TestFunction2, "World", 3.14192654f);
cout << "Delaying a bit..." << endl;
cout << "Doing Function2..." << endl;
CallDelayedFunction (params2);
cout << "Doing Function1..." << endl;
CallDelayedFunction (params1);
cout << "Done" << endl;
}
** Another Update **
There is a third option, as I mentioned in the comments, and that is to use a messaging system. Instead of calling a function, create a message object of the form:-
struct MessageObject
{
int message_id;
int message_size;
};
struct Function1Message
{
MessageObject base;
// additional data
};
and then have a lookup between message_id and actual functions, with the functions and the lookup defined like:-
void Function1 (Function1Object *message)
{
}
struct Lookup
{
int message_id;
void (*fn) (void *data);
};
Lookup lookups [] = { {Message1ID, (void (*) (void *data)) Function1}, etc };