我正在尝试使用函数指针来提高代码效率。但是,我是这个概念的新手,无法在另一个函数中将其用作参数。
这会产生错误“从不兼容的指针类型初始化”。有人可以告诉我我做错了什么,我应该怎么做吗?
执行此操作时:
traverse(node, h, print(node, h));
您实际上是在尝试进行call打印,而不是将指针传递给它。因此,您传递给traverse
的实际上是print
的返回值,而不是指向它的指针。
正确的调用将如下所示:
traverse(node, h, print);
然后在traverse
中调用回调:
void traverse(node_t *node, void *param, func_t func)
{
...
func(node,param);
...
}
但是仍然有问题。函数print
的类型与函数指针func_t
不兼容。前者将FILE *
作为其第一参数,而后者将void *
作为其第二参数。与void *
之间的隐式转换仅在它是转换的源或目标时才起作用。它不适用于功能参数。
假设您需要回调来处理各种不同的类型,可以将print
函数更改为接受void *
并在函数内部转换参数。
void print(node_t *node, void *param)
{
FILE *f = param; // no cast needed
...
首先:仅因为可以使用void*
来代替任何其他对象指针,但这并不意味着指向接受void*
的函数的函数指针与另一个接受FILE*
的函数。
因此,要么必须更改功能指针类型才能与FILE*
一起使用,要么必须更改打印功能才能与void*
一起使用。
然而,编译器错误的原因是您在此处print
调用了实际函数traverse(node, h, print(node, h));
,而不是传递指向该函数的函数指针。由于此函数返回void
,因此编译器会说“嘿,我不能将void参数传递给该函数,而需要一个函数指针”。只需将其更改为:
traverse(node, h, print);
然后traverse
将通过传递的函数指针来调用函数。
关于它的价值,也许您使用的是错误的编程语言:)您打算编写的几乎是C ++,应该是:
traverse(node, [node,h]{ print(node, h); });
然后,遍历将是模板函数,因此您不必只传递一种函数,而可以传递任何函子(可调用对象,例如,实现调用运算符的类:]]]
template <typename Fun> void traverse(node_t *, Fun &&f);
但是您使用了函数指针,因为它是C,并且函数指针不像C ++闭包:它不能携带任何参数。因此,传递参数就在您身上。我想像
FILE*
参数确实来自节点?那是您要代表的目录树吗?
typedef struct { node_t **children; // null-terminated array of child node pointers const char *name; } node_t; typedef void (*cnode_observer_t)(const node_t *, int level, void *); void ctraverse_level(const node_t *node, int level, void *extra, cnode_observer_t cobserver) { cobserver(node, extra); node_t **child = node->children; ++level; while (*child) { ctraverse_level(*child++, level, extra, cobserver); } } void ctraverse(const node_t *node, void *extra, cnode_observer_t cobserver) { ctraverse_level(node, 0, extra, cobserver); } void node_printer(const node_t *node, int level, void *file) { assert(node && file); FILE *f = file; fprintf(f, "%*c%s\n", level, ' ', node->name); } void test(const node_t *node, FILE *file) { ctraverse(node, file, node_printer); }
出于完整性考虑,这是在C ++中的外观:
struct Node {
std::vector<Node> children;
std::string name;
};
template <typename Obs>
void ctraverse(const Node &node, F fun, int level = 0) {
fun(node, level);
++level;
for (auto &n : node.children) {
ctraverse(n, fun);
}
}
void test(const Node &node, std::ostream &out) {
traverse(node, [&](auto &node, int level) {
out << setw(level) << setfill(' ') << " " << node.name << '\n';
});
}