Kaiserludi
Kaiserludi

Reputation: 2472

Calling convention "defines" without #define

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

Answers (1)

Chris Cooper
Chris Cooper

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

Related Questions