C++ 是否可以有通用函数指针?

10

在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?这样,指向两种类型的函数的指针(以及返回指向某些类型的指针且不带参数的其他函数)就可以存储在单个向量中。
2个回答

9

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

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

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

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


好的,有没有一种简单的方法来存储并稍后检索类型,以便可以将其强制转换回来? - jtedit
不是很准确,你需要存储一些枚举或整数代码来表示原始类型,这意味着您必须预先知道可能要存储在向量中的所有可能类型。如果您不需要获取原始类型并且仅从调用函数获取void*就可以,则@n.m.的类型擦除解决方案更简单、更清晰。 - Jonathan Wakely
我需要用它来比较函数的身份,而不是调用它们,所以这个解决方案对我来说非常好。它是否也适用于成员函数? - N0vember
@N0vember 是的,将成员函数指针转换为不同类型的成员函数指针,_然后再转换回来_是有效的。在转换回来之前对其进行任何操作都是未定义的。您不能将其转换为非成员函数指针。 - Jonathan Wakely

8

标准不允许这样做。你可以将函数指针强制转换为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<Myfunc> 存储在你的向量中。
C++11 中更好的解决方案可能是这样的:
template <typename T>
std::function<void*()> castToVoidFunc (T* (*func)())
{
  return [=](){ return func(); };
}

2
标准确实允许强制转换函数指针,可参见[expr.reinterpret.cast]/6,只是在转换后不允许调用它们。在你的 C++11 解决方案中,lambda 表达式是不必要的,std::function<R()>会将返回值转换为 R,如果存在隐式转换序列,则可以直接 return std::function<void*()>(func); - Jonathan Wakely
请参考 [func.wrap.func]/2,它说调用 std::function 使用 INVOKE(..., R) 表单,其中 [func.require]/2 将其定义为将结果隐式转换为 R - Jonathan Wakely

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接