The code below is running correctly with any online gcc compiler I found (gcc 9.2.0), it also run correctly with CYGWIN gcc compiler, but unfortunately it doesn't work well with MINGW gcc compiler - looks like it passes invalid parameter as "this" to "methodA" and "methodB" methods, when they are called, instead of expected results (56,58) i get some random high numbers.
#include <iostream>
using namespace std;
class CallbackBase
{
public:
using METHOD_TYPE = int (CallbackBase::*)(...);
};
class CallbackProvider : public CallbackBase
{
public:
int methodA(int a,int b,int c)
{
return a+b+c+d;
}
int methodB(double a,double b,double c)
{
return a+b+c+d;
}
private:
int d=8;
};
class CallbackRunner
{
public:
CallbackBase::METHOD_TYPE m_method;
CallbackBase* m_this;
void install (CallbackBase* _this, CallbackBase::METHOD_TYPE _method)
{
m_method =_method;
m_this =_this;
}
int Run1()
{
return (m_this->*m_method)(15L,16L,17L);
}
int Run2()
{
return (m_this->*m_method)(15.6,16.7,17.8);
}
};
int main()
{
CallbackProvider cp;
CallbackRunner cr;
cr.install(&cp,(CallbackBase::METHOD_TYPE)&CallbackProvider::methodA);
cout << "result " << cr.Run1() << endl;
cr.install(&cp,(CallbackBase::METHOD_TYPE)&CallbackProvider::methodB);
cout << "result " << cr.Run2() << endl;
return 0;
}
The problem is solved if I add __cdecl attribute to this methods:
int __cdecl methodA(int a,int b,int c)
int __cdecl methodB(double a,double b,double c)
I doesn't use -mrtd compilation flag. According to this, __cdecl should be a default calling convention for gcc compilers but looks like it doesn't the case for MINGW.
Is that possible to set __cdecl as a default calling convention for my project? or as alternative, is there a way to set "default" attribute to all the methods?
I am using Windows 10 with 64 bit architecture.
Your code has a bug - it has undefined behavior. The cast from
int (Class::*)(int, int, int)toint (CallbackBase::*)(...)triggers it. Those two types are not the same, and you can not cast between them willy-nilly.This is an extract of your code where you are attempting this illegal cast:
You can easily see the diagnostic message yourself if you remove the cast:
The fact that it works on some compilers and not on the others is of no significance, it is just a manifestation of undefined behavior.
You could cast back to the original function type before calling it, but than the whole thing would become even more ugly.
Another option might be to make your concrete functions variadic as well, and access parameters via
VA_ARGS. This would throw the whole C++ type safety off the window, and I do not like this approach either.Just for the trivia, it looks like mingw's gcc uses a legacy calling convention (
cdeclis indeed quite legacy) for variadic functions, while other compilers would use modern AMD ABI.