将函数分配给具有相同签名但不同调用约定的 std::function 失败

assigning functions to std::function with same signature, but different calling convention fails

本文关键字:调用 约定 std 失败 function 分配 函数      更新时间:2023-10-16

下面的编译和使用 mingw 4.7.2 和 -m64 标志运行良好。

但是对于 -m32 或任何 mingw 32 位版本,它无法编译。 这是一个错误还是我缺少编译器标志?

    #include <iostream>
    #include <functional>
    using namespace std;
    int __cdecl ccall(int i)
    {
        cout << i << endl;
        return 0;
    }
    int __stdcall stdcall(int i)
    {
        cout << i << endl;
        return 0;
    }
    int __fastcall fastcall(int i)
    {
        cout << i << endl;
        return 0;
    }

    int main() {
        std::function<int(int)> fnc = ccall;
        fnc(10);
        std::function<int(int)> fnstd = stdcall;
        fnstd(100);
        std::function<int(int)> fnfast = fastcall;
        fnfast(200);
        return 0;
    }

错误信息:

    ...LocalTempcc4ekW9J.s: Assembler messages:
    ...LocalTempcc4ekW9J.s:30: Error: symbol `__ZNSt17_Function_handlerIFiiEPFiiEE9_M_invokeERKSt9_Any_datai' is already defined 
    ...LocalTempcc4ekW9J.s:80: Error: symbol `__ZNSt14_Function_base13_Base_managerIPFiiEE10_M_managerERSt9_Any_dataRKS4_St18_Manager_operation' is already defined
    ...LocalTempcc4ekW9J.s:114: Error: symbol `__ZNSt14_Function_base13_Base_managerIPFiiEE10_M_managerERSt9_Any_dataRKS4_St18_Manager_operation' is already defined

在将调用"隐藏"在 lambda 函数中后,我最终以这种方式这样做,它工作得很好:

    template<class Ret, class... Args> class StdCall
    {
    public:
        typedef Ret(__stdcall Fn_t)(Args...);
        typedef std::function<Ret (Args...)> Functor_t;
        Functor_t get(Fn_t pFn)
        {
            return [pFn](Args... as){
                return pFn(as...);
            };
        }
    };
    auto fn1 = CdeclCall<int,int>().get( ccall );
    auto fn2 = StdCall<int,int>().get( stdcall );
    fn1(123);
    fn2(156);

算自己很幸运。想想使用错误的调用约定的函数调用可能导致的破坏!哦,只需创建一个具有"正确"调用约定的填充程序函数,该约定调用"错误"的调用约定。也许您可以将其隐藏在单独编译的文件中。