我继承了一些 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;
}
该代码在 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
^
恕我直言,这段代码正在对编译器的底层机制做出假设。或者也许这些假设对所有 C++ 编译器都有效 - 有人可以帮忙吗?
(在实际代码中,我们按名称在映射中存储一大堆函数指针。这些函数都有不同的签名,这就是为什么它们都被转换为相同的签名 void(*)(void) 的原因。这是类似的到上面的 myStoredFunction。然后它们在调用时被转换为单独的签名,类似于上面的 myExtractedFunction。)
创建完全避免强制转换的函数怎么样:
template <typename C, void (C::*M)()>
void AsFunc(void* p)
{
(static_cast<C*>(p)->*M)();
}
then
void (*myExtractedFunction)(void*) = &AsFunc<MyClass, &MyClass::myMemberFunc>;
在 C++17 中,具有某些特征,您甚至可能有template <auto *M> void AsFunc(void* p)
and void(*myStoredFunction)(void*) = &AsFunc<&MyClass::myMemberFunc>;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)