【问题标题】:C++ Is it possible to have a generic function pointer?C++ 是否有可能有一个通用的函数指针?
【发布时间】:2013-05-12 15:09:05
【问题描述】:

在 C++ 中是否可以创建某种通用函数指针,指向返回指向某种类型的指针且不带参数的任何函数?

例如,一种类型的指针可以指向以下两个:

int* funcInt(){
    int* i = new int;
    *i = 5;
    return i;
}

char* funcChar(){
    char* c = new char;
    *c = 'a';
    return c;
}

显然以下是有效的:

int* (*funcPointerA)() = funcInt;
char* (*funcPointerB)() = funcChar;

但是是否可以执行以下操作(此时会出现编译错误):

void* (*funcPointerC)() = funcInt;
void* (*funcPointerD)() = funcChar;

目前上面的代码给出以下错误:

error: invalid conversion from 'int* (*)()' to 'void* (*)()'
error: invalid conversion from 'char* (*)()' to 'void* (*)()'

有没有办法将 funcPointerA 和 B 转换为 C 和 D?

这样可以将指向这两种函数类型的指针(以及其他返回指向某种类型的指针但不带参数的函数)的指针一起存储在一个向量中。

【问题讨论】:

    标签: c++ function generics pointers


    【解决方案1】:

    有没有办法将 funcPointerA 和 B 转换为 C 和 D?

    是的,您可以将一种类型的函数指针显式转换为另一种类型:

    void* (*funcPointerC)() = reinterpret_cast<void*(*)()>(funcInt);
    

    但是调用转换结果是未定义的行为,您必须先将其转换回原来的类型。如果您可以记录原始类型并安排将指针转换回原始类型,那么您的代码就可以工作。

    【讨论】:

    • 好的,有没有一种简单的方法来存储和稍后检索类型以便可以将其转换回?
    • 并非如此,您需要存储一些枚举或整数代码来说明原始类型是什么,这意味着您必须提前知道您可能想要存储在向量中的所有可能类型.如果您不需要返回原始类型并且只需从调用函数中返回 void* 就可以了,那么 @n.m. 的类型擦除解决方案更简单、更干净
    • 我需要这个来比较函数的身份,而不是调用它们,所以这个解决方案对我来说很棒。它是否也适用于成员函数?
    • @N0vember 是的,将指向成员函数的指针转换为指向成员函数的不同类型的指针然后再返回是有效的。在再次将其转换回来之前对其进行任何操作都是未定义的。您不能将其转换为指向非成员函数的指针。
    【解决方案2】:

    标准不允许这样的事情。将函数指针转换为void* (*)() 可能会也可能不会。在 C++ 中有符合标准的解决方案。这是一个简单的 C++11 之前的版本:

    struct MyFunc
    {
      virtual void* operator()() = 0;
      virtual ~Myfunc(){}
    };
    
    template <typename T>
    struct MyfuncImpl
    {
      typedef T TFunc();
      MyfuncImpl (TFunc* func) : m_func(func) {}
      void* operator()() { return m_func(); }
     private:
      TFunc* m_func;
    };
    

    现在您可以将shared_ptr&lt;Myfunc&gt; 存储在您的向量中。

    C++11 中更好的解决方案可能如下所示:

    template <typename T>
    std::function<void*()> castToVoidFunc (T* (*func)())
    {
      return [=](){ return func(); };
    }
    

    【讨论】:

    • 标准确实允许转换函数指针,参见[expr.reinterpret.cast]/6,它只是不允许在转换后调用它们。 C++11 解决方案中的 lambda 是不必要的,如果存在隐式转换序列,std::function&lt;R()&gt; 会将返回值转换为 R,因此您只需 return std::function&lt;void*()&gt;(func);
    • 参见 [func.wrap.func]/2,它说调用 std::function 使用 INVOKE(..., R) 形式,其中 [func.require] /2 定义为将结果隐式转换为R
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-16
    • 2010-09-22
    • 1970-01-01
    相关资源
    最近更新 更多