Nig*_*arp 3 c++ member-function-pointers
我继承了一些C ++代码,并且承担了摆脱警告的任务。
在这里,我们有一个成员函数指针被转换为一个函数指针。我知道成员函数指针与函数指针“不同”,因为在内部有一个隐含的“ this”参数。但是,我的前任似乎已经明确地利用了这一事实,即从成员函数指针转换为插入了附加第一个参数的函数指针。
我的问题是:
A)我可以摆脱编译器警告吗?
B)该代码在什么程度上可以保证工作?
为了这个问题,我将其缩减为一个小的main.cpp:
#define GENERIC_FUNC_TYPE void(*)(void)
#define FUNC_TYPE int(*)(void *)
class MyClass
{
public:
MyClass(int a) : memberA(a) {}
int myMemberFunc()
{
return memberA;
}
private:
int memberA;
};
int main(int argc, char*argv[])
{
int (MyClass::* memberFunc) () = &MyClass::myMemberFunc;
MyClass myObject(1);
std::cout << (myObject.*memberFunc)() << std::endl;
// All good so far
// Now get naughty, store it away in a very basic fn ptr
void(*myStoredFunction)(void) = (GENERIC_FUNC_TYPE)memberFunc; // Compiler warning
// Reinterpret the fn pointer as a pointer to fn, with an extra object parameter
int (*myExtractedFunction)(void*) = (FUNC_TYPE)myStoredFunction;
// Call it
std::cout << myExtractedFunction(&myObject) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
该代码在g ++下以一个警告进行编译,并按预期输出两个1:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:27:53: warning: converting from ‘int (MyClass::*)()’ to ‘void (*)()’ [-Wpmf-conversions]
void(*myStoredFunction)(void) = (GENERIC_FUNC_TYPE)memberFunc; // Compiler warning
^
Run Code Online (Sandbox Code Playgroud)
恕我直言,此代码对编译器的基本机制进行了假设。也许这些假设对所有C ++编译器都有效-有人可以帮忙吗?
(在实际代码中,我们按名称在地图中存储了一堆函数指针。这些函数都有不同的签名,这就是为什么它们都被强制转换为相同的签名void(*)(void)。这是类似的到上面的myStoredFunction。然后在调用时将它们强制转换为单个签名,类似于上面的myExtractedFunction。)
如何创建完全避免强制转换的函数:
template <typename C, void (C::*M)()>
void AsFunc(void* p)
{
(static_cast<C*>(p)->*M)();
}
Run Code Online (Sandbox Code Playgroud)
然后
void(*myStoredFunction)(void) = &AsFunc<MyClass, &MyClass::myMemberFunc>;
Run Code Online (Sandbox Code Playgroud)
在C ++ 17中,具有某些特征,您甚至可能拥有template <auto *M>
void AsFunc(void* p)和void(*myStoredFunction)(void) = &AsFunc<&MyClass::myMemberFunc>;