我从here找到了一个“技巧”,可以使用以下方法将任何类型转换为另一种类型:
template<typename OUT, typename IN>
OUT ForceCast(IN in)
{
union
{
IN in;
OUT out;
}
u = { in };
return u.out;
};
然后我尝试了下面的代码:
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;
}
我用 MSVC 编译了代码,没有错误,它按预期运行,输出为
Hello!
。
据我所知,C++ 编译器会隐式地将
this
指针传递给成员函数。最后 2 段中的答案here表示作者听到的所有 ABI 都将 this
指针作为第一个参数传递。
所以我有两个问题:
this
指针作为第一个参数传递?std::function
。如果第一个问题是正确的,这个“技巧”是否还有其他潜在的副作用? (示例代码:这里)暂时忽略它是否有保证(其他人肯定可以向您提供有关标准内容以及其他编译器做什么的详细信息) - 即使实际上,仅在 MSVC 上,您也会遇到一个问题。 x64-windows 调用约定确实传递“this”作为第一个参数,但是成员函数和自由函数之间有一个主要区别:
如果返回值无法在 RAX 中返回,则必须将指针传递给函数。在自由函数的情况下,MSVC 要求该指针作为第一个寄存器 (RCX) 传递,并且所有其他参数都移位 1。 对于成员函数,必须将 this 指针传递到“this”参数 (RDX) 之后的第一个寄存器中,并且所有其他参数都会移位 1。 我知道这一点是因为我最近为我的 JIT 编译器实现了本机 x64 调用约定,并且遇到了完全相同的问题 - 我必须更改返回处理的参数顺序,具体取决于它是成员还是免费功能。
几乎意味着,你尝试的东西不能被概括,即使只是在 MSVC 上 - 它永远不会实现像 std::function 这样的东西。这甚至没有讨论成员函数指针实际上根本不是常规指针的其他问题 - 例如,当多路复用/虚拟继承发挥作用时,MSVC 会使这些指针更大,需要更多数据来修复“this”。