Why do i get "Error: symbol is already defined" when instantiating a C++ template with function type

Why do i get "Error: symbol is already defined" when instantiating a C++ template with function type

我有一个包含 4 个函数的简单 DLL 库,其中 2 个使用 __stdcall 和 2 个默认 __cdecl 调用约定。

在我的可执行文件中,我想调用所有这 4 个函数,并且我正在为其使用一个模板。代码如下:

#include <windows.h>
#include <stdio.h>

template<typename FuncType>
void CallFunction( HMODULE hModule, const char * name )
{
    FuncType function = (FuncType)GetProcAddress( hModule, name );
    if (function)
        printf("result: %d.\n", function(1,2) );
    else
        printf("%s not found (%lu)\n", name, GetLastError());
}

typedef int (* FuncType1)(int, int);
typedef int (__stdcall * FuncType2)(int, int);

int main(int argc, char** argv)
{
    HMODULE hModule = LoadLibrary( TEXT("library.dll") );
    if (hModule) {
        CallFunction<FuncType1>( hModule, "File1_Funkce1" );
        CallFunction<FuncType2>( hModule, "File1_Funkce2" );
        CallFunction<FuncType1>( hModule, "File2_Funkce1" );
        CallFunction<FuncType2>( hModule, "File2_Funkce2" );

        FreeLibrary( hModule );
    }
    else {
        printf("library not found\n");
    }
    return 0;
}

这在 Visual Studio 编译器中编译得很好,但在 MinGW 中会抛出错误: Error: symbol '__Z12CallFunctionIPFiiiEEvP11HINSTANCE__PKc' is already defined。我不明白为什么以这种方式使用模板会导致多个定义,因为您通常可以在同一个翻译单元中多次实例化 vector<int>vector<char> 并且不会发生错误。

有什么想法吗?

编辑: 我的编译命令很简单:

cl file.cpp
g++ file.cpp -o file.exe

似乎 mingw 在修改模板名称时忽略了 __stdcall 并导致名称冲突。您可以通过将这些指针编码为它们自己的类型来避免这种情况:

template<typename Func>
struct StdCall;

template<typename R, typename... Params>
struct StdCall<R(Params...)>
{
    using type = R(__stdcall *)(Params...);
};

template<typename Func>
struct Cdecl;

template<typename R, typename... Params>
struct Cdecl<R(Params...)>
{
    using type = R(*)(Params...);
};

然后你会打电话给他们:

CallFunction<StdCall<int(int,int)>>();
CallFunction<Cdecl<int(int,int)>>();

您必须更改 CallFunction 才能调用 ::type,但是:

template<typename FuncType>
void CallFunction( )
{
    using Func = typename FuncType::type;
}