user12758366
user12758366

Reputation:

Using Function Pointer as method parameter

I am trying to use a function pointer to make my code more efficient. However, I am new to this concept and am having trouble using it as a parameter inside another function.

this gives an error "initialization from incompatible pointer type". Can someone tell me what I am doing wrong and what I should do instead?

Upvotes: 2

Views: 155

Answers (3)

For what it's worth, perhaps you're using the wrong programming language :) What you intended to write is pretty much C++, where it'd be:

traverse(node, [node,h]{ print(node, h); });

Then, traverse would be a template function, so that you're not constrained to passing just one kind of a function, but instead could pass any functor (a callable object, e.g. a class implementing the call operator):

template <typename Fun> void traverse(node_t *, Fun &&f);

But you've used a function pointer, since it's C, and a function pointer is not like the C++ closure: it can carry no parameters. Thus, passing the parameters is on you. I imagine that the FILE* argument really comes from the node? Is that a directory tree you're trying to represent?

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);
}

For completeness' sake, here's how it'd look in 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';
  });
}

Upvotes: 0

Lundin
Lundin

Reputation: 213960

First of all: just because a void* can be used in place of any other object pointer, that does not mean that a function pointer to a function accepting a void* is compatible with another function accepting a FILE*.

So you either have to change your function pointer type to work with FILE*, or you have to change the print function to work with void*.

The reason for the compiler error is however that you call the actual function print here traverse(node, h, print(node, h));, rather than passing on the function pointer to it. Since this function returns void, the compiler says "hey I can't pass a void parameter to this function expecting a function pointer". Simply change this to:

traverse(node, h, print);

and then traverse will call the function through the passed function pointer.

Upvotes: 1

dbush
dbush

Reputation: 224082

When you do this:

traverse(node, h, print(node, h));

You're actually attempting to call print instead of passing a pointer to it. So what you're passng to traverse is actually the return value of print instead of a pointer to it.

The proper call would look like this:

traverse(node, h, print);

Then inside of traverse you would call the callback:

void traverse(node_t *node, void *param, func_t func)
{
    ...
    func(node,param);
    ...
}

There's still a problem however. The type of the function print is not compatible with the function pointer func_t. The former takes a FILE * as its first parameter while the latter takes a void * for its second parameter. The implicit conversion to/from a void * only works when it is the source or destination of the conversion. It does not apply to function parameters.

Assuming you need the callback to handle various different types, you can change the print function to accept a void * and convert the parameter inside of the function.

void print(node_t *node, void *param)
{
    FILE *f = param;  // no cast needed
    ...

Upvotes: 4

Related Questions