如何使一个以任意函数指针为参数的函数?

Posted

技术标签:

【中文标题】如何使一个以任意函数指针为参数的函数?【英文标题】:How can you make a function that takes as a parameter an arbitrary function pointer? 【发布时间】:2018-04-15 03:28:28 【问题描述】:

我正在尝试执行以下操作,但我什至不确定是否可行。

我想要一个接收任意函数指针的函数,以将其传递给不同的函数(我知道这是代码异味,我现在不想讨论良好的软件工程实践)。

换句话说,我正在寻找的东西看起来像:

void method1(arbitraty pointer p)

    method2(p);

我不确定是否有办法声明任意函数指针(返回值保证为void但参数是任意的,无论是数量还是类型)​​

【问题讨论】:

打开你的 C++ 书籍到教你如何使用模板的章节。模板是现代 C++ 中最先进的部分之一,因此,***.com 上的简短一/两段答案不足以解释该主题。你需要自己研究这个主题,用一本好书。 我猜你可以传递一个 void 指针并强制转换它,但如果你打算从方法 2 内部调用函数,我肯定会抱怨代码异味 - 具有不同数量参数的函数不能互换- 他们对堆栈指针所做的更改被烘焙到生成的代码中,因此如果你施放例如你会破坏你的堆栈。一个 2 参数函数指针指向一个 1 参数函数指针并调用它。顺便说一句,我喜欢上面评论中的“模板”答案——你应该调查一下。也有可变参数模板,也许这些会起作用。 你打算用method2中的那个指针做什么? 完整的问题是我正在尝试为未来项目的 GLFW 窗口制作一个包装类。我正在尝试通过此方法设置每个 GLFW 回调函数到目前为止的方法一直在滥用这样一个事实,即大多数 GLW 回调函数具有不同的签名并且只是复制 [licate 每个回调函数的代码 完整的故事很好,花花公子,但重要的问题是你打算用method2中的指针做什么?显示使用它的代码行。跨度> 【参考方案1】:

仅当推导的类型是函数指针类型时,才使用模板并使用 SFINAE 启用它:

template <typename T, std::enable_if_t<std::is_function<T>::value, int> = 0>
void method1(T* p)

    // ...

【讨论】:

【参考方案2】:

这可能被某些人认为是过度设计,但您可以尝试以下方法:

为您感兴趣的每个回调创建一个枚举:

enum GlfwCallback 
    KeyCallback,
    FramebufferSizeCallback,
    // etc.
;

然后创建一个类型族,将它们中的每一个与相应的函数指针类型相关联。通过创建模板结构并反复对其进行专门化来做到这一点:

template<GflwCallback callback>
struct GlfwCallbackType ;

template<>
struct GlfwCallbackType<KeyCallback> 
    using CallbackType = GLFWkeyfun;
    // or
    using CallbackType = void(*)(GLFWwindow *, int, int, int, int);
;

template<>
struct GlfwCallbackType<FramebufferSizeCallback> 
    using CallbackType =  GLFWframebuffersizefun;
;

// etc.

那你就可以写了

template<GlfwCallback callback>
void method1(GlfwCallbackType<callback>::CallbackType p) 
    // do something with p
    method2<callback>(p);
;

另外,请注意,您可以根据应用程序的需要将其他类型甚至静态函数和数据成员添加到“类型族”中。

【讨论】:

在这一点上我觉得我还不如坚持滥用签名:P【参考方案3】:

使用函子(即为operator() 定义重载的类)以一种不错的、类型安全的方式做你想做的事的可能性。 由于仿函数是一个类,您可以将参数设置为数据成员,并将您想要作为任意指针传递的函数的实现/调用移动到 operator() 方法中,您可以通过该方法访问所有参数this 指针。

此外,您可以定义函子的层次结构,每个函子都有专门的参数和实现,因此您可以修改 method2 的签名,如下所示:

method2(BaseFunctor* myfunctor) 
   if (myfunctor) 
      (*myfucntor)();
 

并在调用上下文中设置正确类型的仿函数对象。

还可以查看 lambdas (c++11),它基本上是函子定义的捷径。

【讨论】:

以上是关于如何使一个以任意函数指针为参数的函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使函数返回指向函数的指针? (C++)

C语言中 指针做函数参数传递二维数组

在以抽象基类为参数的函数中将指针和赋值运算符与派生类一起使用

OC(C语言特性函数,指针)

C语言如何声明一个返回函数指针的函数?

退出此函数后,为什么指针变量的值没有传递给指针参数?