Reputation: 2472
In Microsoft's WinDef.h several #defines for callbacks are introduced:
#ifdef _MAC
#define CALLBACK PASCAL
#define WINAPI CDECL
#define WINAPIV CDECL
#define APIENTRY WINAPI
#define APIPRIVATE CDECL
#ifdef _68K_
#define PASCAL __pascal
#else
#define PASCAL
#endif
#elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
#define APIPRIVATE __stdcall
#define PASCAL __stdcall
#else
#define CALLBACK
#define WINAPI
#define WINAPIV
#define APIENTRY WINAPI
#define APIPRIVATE
#define PASCAL pascal
#endif
Is there a way to do something like that without preprocessor macros? I would like to have something, that resolves to different calling conventions on Unix and Windows, but which - unlike a macro - can be namespaced.
I have tried "typedef __stdcall test;" but that doesn't compile.
EDIT - here is an example usage scenario:
namespace Thread
{
typedef startRoutineReturnType (startRoutineCallingConvention *startRoutineCallback)(void* pArg);
}
Thread::startRoutineReturnType Thread::startRoutineCallingConvention startRoutine(void* pArg);
This way startRoutine can confirm to the signature of that callback on all platforms although the calling convention of the callback differs between platforms. When there is the possibility that a lot of functions have to confirm to that callback signature then something like
#ifdef UNIX
void* foo(void* pArg)
#elif WINDOWS
DWORD WINAPI foo(LPVOID pArg)
#else
// something else
#endif
{
// body
}
instead looks quite messy.
Upvotes: 4
Views: 1719
Reputation: 432
It's a terrible hack in my opinion, but I tried seeing if I could do it with template specializations and it actually worked. Try this:
#include <iostream>
enum CALLCONVENTION
{
STDCALL,
CDECL
};
template <CALLCONVENTION Convention>
void Function()
{
}
template<>
void __stdcall Function<STDCALL>()
{
std::cout << "STDCALL" << std::endl;
}
template<>
void __cdecl Function<CDECL>()
{
std::cout << "CDECL" << std::endl;
}
namespace StdCall
{
void Foo()
{
Function<STDCALL>();
}
}
namespace CDecl
{
void Foo()
{
Function<CDECL>();
}
}
int main(void)
{
Function<STDCALL>();
Function<CDECL>();
StdCall::Foo();
CDecl::Foo();
return 0;
}
It compiles and works on Visual Studio 2010.
Upvotes: 3