有没有办法传递带泛型参数的函数指针?

Osa*_*afa 6 c function-pointers

我正在实现一个通用的单链表,其中列表节点存储指向其数据的指针.

typedef struct sll_node
{   
    void *data;
    struct sll_node *next;
} sll_node;
Run Code Online (Sandbox Code Playgroud)

为了实现一个适用于任何类型数据的通用查找子例程,我编写了它,以便它将一个函数指针作为参数作为参数,如下所示:

/* eq() must take 2 arguments. ex: strcmp(char *, char *) */
sll_node *sll_find(void *data, int (*eq)(), sll_node *root);
Run Code Online (Sandbox Code Playgroud)

您可以传递适用于手头数据类型的函数指针.因此,如果在列表节点中存储字符串,则可以将strcmp作为eq()函数传递,依此类推.它有效,但我仍然不满意..

有没有办法明确指定比较函数参数的数量而不放弃它的一般性?

我一开始尝试了这个:

sll_node *sll_find(void *data, int (*eq)(void *, void *), sll_node *root);
Run Code Online (Sandbox Code Playgroud)

我希望它能起作用.但是没有(编辑:它编译了一个警告,但我有 - 错误!),我不得不围绕strcmp编写一个包装函数,使其符合eq原型.

然后我尝试了:

sll_node *sll_find(void *data, int (*eq)(a, b), sll_node *root);
Run Code Online (Sandbox Code Playgroud)

要么:

typedef int (*equality_fn)(a, b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
Run Code Online (Sandbox Code Playgroud)

这两个都不会编译,因为:"只有函数定义才允许没有类型的参数列表"

use*_*109 2

要在没有包装器或强制转换的情况下使用strcmp,声明需要是

sll_node *findNode(void *data, int (*eq)(const char *, const char *), sll_node *root);
Run Code Online (Sandbox Code Playgroud)

另一方面,如果将 args 声明为const void *,则可以通过强制转换strcmp为适当的类型来避免包装器。

方法一:直接施法,比较乱但是有效

    result = findNode( "hello", (int(*)(const void *, const void *))strcmp, root );
Run Code Online (Sandbox Code Playgroud)

方法2:typedef比较函数,然后用它来强制转换

typedef int (*cmpfunc)(const void *, const void *);
result = findNode( "world", (cmpfunc)strcmp, root );
Run Code Online (Sandbox Code Playgroud)

编辑:读完@WilburVandrsmith 链接的这篇文章后,我决定保留这个答案。我让读者自行决定提议的演员阵容是否违反规范中的以下段落:

如果转换后的指针用于调用类型与指向的类型不兼容的函数,则行为未定义。

兼容还是不兼容,这是一个问题,你决定。

  • 尽管转换函数指针通常会起作用,但不幸的是,[这在技术上仍然是未定义的行为](/sf/ask/39170701/)。 (2认同)