【问题标题】:How to cast void pointers to function pointers如何将 void 指针转换为函数指针
【发布时间】:2019-08-09 18:35:30
【问题描述】:

我正在尝试编写一个将附加一些函数指针的类。

这个指针会被这个类的另一个方法调用。我将把函数指针存储在一个 void* 向量上,这样任何东西都可以放在一个向量上,而不是每种类型的不同向量。

我打算为我需要从类内部调用的任何不同函数声明不同的 AppendCallback 方法,例如:

void MyClass:AppendCallback(void (*Callback)())
{
    _CallbackVector.push_back((void*)Callback);
    _IdVector.push_back(VoidID);
}

void MyClass:AppendCallback(void (*Callback)(uint32_t));
void MyClass:AppendCallback(void (*MyOtherClass::Callback)());
void MyClass:AppendCallback(void (*MyOtherClass::Callback)(uint32_t));

将有第二个向量,它只包含标识符以知道 void* 指向什么,这也将在 AppendCallback 方法上分配。

如何将 void 指针再次转换为调用这些函数的函数指针?

也许是这样的?

void MyClass::Service(uint32_t x)
{
    for(uint i = 0; i < _CallbackVector.size(); i++)
    {
        switch(_IdVector[i])
        {
            case VoidID: void(*_CallbackVector[i]()); break;
            case Uint32ID: void(*_CallbackVector[i](x)); break;
        }
    }
}

编辑:

这是从 void* 转换为函数指针的正确方法吗?

【问题讨论】:

  • 是的,您必须自己存储某种类型信息。
  • iirc,在 C++ 中,没有规定将函数指针存储到 void* 中,也没有规定将 void* 转换回函数指针。它可能适用于您的平台,但我认为它是 UB。您可能想在这个问题中添加language-lawyer
  • 这并没有解决问题,但以下划线开头的名称后跟大写字母(_CallbackVector_IdVector)和包含两个连续下划线的名称保留供执行。不要在你的代码中使用它们。
  • void* 不需要足够大以容纳函数指针。阅读std::function

标签: c++ methods casting language-lawyer


【解决方案1】:

That's not allowed in C++:

在 C++98/03 中不允许将 void* 直接转换为函数指针(不应使用任何类型转换进行编译)。 C++0x 有条件地支持它(一个实现可以选择定义行为,如果它确实定义了它,那么它必须按照标准所说的去做。一个 void*,由 C++98/03 定义标准,旨在指向对象,而不是包含函数指针或成员指针。

And again:

你不能。

您可以将数据指针强制转换为 void*,然后返回到您开始使用的相同指针类型。 std::function 不是指针类型,因此强制转换是静态无效的,并且与您开始使用的不同。您从 void()() 类型的 .target 开始,但它不是数据指针,而是函数指针,因此将其转换为 void 并返回是实现定义的。

在你的具体情况下,你可以尝试这样的事情:

class PointerToFunction {

};

template <typename Type>
class PointerToFunctionType : public PointerToFunction, std::function<Type> {
    public:
        using std::function<Type>::function; // I think this is the right syntax for this trick: https://softwareengineering.stackexchange.com/a/197901/342247


};

// Now, we can do this:

std::vector<PointerToType*> _CallbackVector;

基本上,我们使用类似于how boost::any/std::any (since C++17) is implemented 的继承技巧将任何std::function 存储在指针中。唯一的问题是知道如何将其转换回来。正确执行此操作取决于您希望如何将 void* 转换回开头(即知道它的类型),所以我将把这部分留给您。

【讨论】:

    猜你喜欢
    • 2012-11-21
    • 1970-01-01
    • 2011-07-31
    • 2018-12-10
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多