I found a "trick" from here to cast any type into another type by using:
template<typename OUT, typename IN>
OUT ForceCast(IN in)
{
union
{
IN in;
OUT out;
}
u = { in };
return u.out;
};
Then I tried the code below:
class C1
{
public:
void Test(void)
{
std::cout<<"Hello!"<<std::endl;
}
};
int main()
{
C1 obj;
void* function = ForceCast<void*>(&C1::Test);
((void(*)(void*))function)(&obj);
return 0;
}
I compiled the code with MSVC without errors, and it ran as expected with an output of Hello!
.
As I know, C++ compilers will implicitly pass this
pointer into member functions. And the answer here in the last 2 paragraphs says all ABIs that the author heard of do pass the this
pointer as the 1st parameter.
So I have 2 questions:
Is it true that modern C++ compilers, including those for embedded systems (like ARMCC etc), pass the this
pointer as the 1st parameter?
I want to use this "trick" to build an easy-to-use and low overhead callback system without using the "heavy" std::function
. If the 1st question is true, is there any other potential side effect with this "trick"? (Sample code: here)
Ignoring whether or not it's guaranteed for now (somebody else can certainly give you the details on what the standard say, and what other compilers do) - even practically, just on MSVC, you have one problem. The x64-windows calling convention does pass "this" as the first argument, however there is one major difference between a member-function and a free function:
In case of a return-value, that cannot be returned in RAX, a pointer has to passed to the function. In the case of a free-function, MSVC mandates that this pointer is passed as the first register (RCX), and all other arguments get shifted by 1. For a member-function, this pointer has to be passed in the first register after the "this" argument (RDX), and all other arguments are shifted by 1. I know this because I recently implement the native x64-calling convention for my JIT compiler, and ran into the exact same problem - where I had to change up the order of parameters for return-handling, depending on whether it's a member or a free function.
Pretty much means that, what you attempt cannot be generalized, even on just MSVC - it will never work to implement something like std::function, which has to deal with different types of return-values). That is not even talking about other issues with member-function pointers not actually being regular pointers at all - MSVC will for example make those pointers larger, when multiplex/virtual inheritance is in play, where more data is required to fixup "this".