【问题标题】:assigning functions to std::function with same signature, but different calling convention fails将函数分配给具有相同签名但不同调用约定的 std::function 失败
【发布时间】:2013-01-31 13:01:09
【问题描述】:

以下编译并使用 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;
    }

错误信息:

    ...\Local\Temp\cc4ekW9J.s: Assembler messages:
    ...\Local\Temp\cc4ekW9J.s:30: Error: symbol `__ZNSt17_Function_handlerIFiiEPFiiEE9_M_invokeERKSt9_Any_datai' is already defined 
    ...\Local\Temp\cc4ekW9J.s:80: Error: symbol `__ZNSt14_Function_base13_Base_managerIPFiiEE10_M_managerERSt9_Any_dataRKS4_St18_Manager_operation' is already defined
    ...\Local\Temp\cc4ekW9J.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);

【问题讨论】:

  • 请注意,这个调用约定是非标准的
  • 在 64 位机器上只有__fastcall。这就是它适用于 64 位编译的原因。 __stdcall__cdecl 会被 x64 编译器简单地忽略。
  • 使用std::function&lt;int __stdcall (int)&gt; fnstd = stdcall;std::function&lt;int __fastcall (int)&gt;会有帮助吗?
  • 坦克为你解答。但编译器不喜欢这种语法:错误:变量'std::function fnstd'有初始化程序但类型不完整我最终这样做了:模板类 StdCall { public: typedef Ret(__stdcall Fn_t)(Args...); typedef std::function Functor_t; Functor_t get(Fn_t pFn) { return [pFn](Args... as){ return pFn(as...); }; } }; auto fn1 = CdeclCall().get(ccall); auto fn2 = StdCall().get(stdcall); fn1(123); fn2(156);
  • 对于那些乱七八糟的评论感到抱歉。我用我的“解决方案”编辑了我的初始帖子

标签: c++ mingw std-function stdcall cdecl


【解决方案1】:

算你自己幸运。想想调用约定错误的函数调用可能造成的破坏!哦,只需使用调用“错误”的“正确”调用约定创建一个 shim 函数。也许您可以将其隐藏在单独编译的文件中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-04
    • 1970-01-01
    • 2010-09-29
    • 2011-01-24
    相关资源
    最近更新 更多