Присваивание функций std::function с одинаковой сигнатурой, но другое соглашение о вызовах не выполняется

Следующий компилируется и прекрасно работает с флагами mingw 4.7.2 и -m64.

но с -m32 или с любым 32-разрядным выпуском mingw он не скомпилируется. это ошибка или мне не хватает флага компилятора?

    #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

я закончил тем, что делал это таким образом после того, как "скрыл" вызов в лямбда-функции, она работает просто отлично:

    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);

1 ответ

Считай, что тебе повезло. Подумайте о том, какой хаос может вызвать вызов функции с неправильным соглашением о вызовах! Да, и просто создайте функцию shim с "правильным" соглашением о вызовах, которое вызывает "неправильное". Возможно, вы можете скрыть это в отдельно скомпилированном файле.

Другие вопросы по тегам