4

在 Microsoft 的 WinDef.h 中,引入了几个回调的#defines:

#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

有没有办法在没有预处理器宏的情况下做类似的事情?我想要一些东西,它可以解决 Unix 和 Windows 上的不同调用约定,但是 - 与宏不同 - 可以命名空间。

我试过“typedef __stdcall test;” 但这不会编译。

编辑 - 这是一个示例使用场景:

namespace Thread
{
    typedef startRoutineReturnType (startRoutineCallingConvention *startRoutineCallback)(void* pArg);
}

Thread::startRoutineReturnType Thread::startRoutineCallingConvention startRoutine(void* pArg);

这种方式 startRoutine 可以在所有平台上确认该回调的签名,尽管回调的调用约定在平台之间有所不同。当有可能很多函数必须确认该回调签名时,就像

#ifdef UNIX
    void* foo(void* pArg)
#elif WINDOWS
    DWORD WINAPI foo(LPVOID pArg)
#else
    // something else
#endif
{
    // body
}

相反,看起来很乱。

4

1 回答 1

3

在我看来,这是一个可怕的 hack,但我尝试看看我是否可以使用模板专业化来做到这一点,并且它确实有效。尝试这个:

#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;
}

它在 Visual Studio 2010 上编译和工作。

于 2013-07-17T17:48:08.817 回答