我可以合法地将成员函数指针转换为函数指针吗?

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。)

Jar*_*d42 6

如何创建完全避免强制转换的函数:

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>;