Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ function pointers, again. Confusion regarding syntax

On this page I found a good example of function pointers in C++ (as well as of functors, but this question isn't about functors). Below is some copypasta from that page.

#include <iostream>

double add(double left, double right) {
  return left + right;
}

double multiply(double left, double right) {
  return left * right;
}

double binary_op(double left, double right, double (*f)(double, double)) {
  return (*f)(left, right);
}

int main( ) {
  double a = 5.0;
  double b = 10.0;

  std::cout << "Add: " << binary_op(a, b, add) << std::endl;
  std::cout << "Multiply: " << binary_op(a, b, multiply) << std::endl;

  return 0;
}

I understand the code in general terms, but there are a couple of things that I've always found confusing. Function binary_op() takes a function pointer *f, but when it's used, for example on line 19 binary_op(a, b, add), the function symbol add is passed in, not what one would think of as its pointer, &add. Now you may say that this is because the symbol add is a pointer; it's the address of the bit of code corresponding to the function add(). Very well, but then there still seems to be a type discrepancy here. The function binary_op() takes *f, which means f is a pointer to something. I pass in add, which itself is a pointer to code. (Right?) So then f is assigned the value of add, which makes f a pointer to code, which means that f is a function just like add, which means that f should be called like f(left, right), exactly how add should be called, but on line 12, it's called like (*f)(left, right), which doesn't seem right to me because it would be like writing (*add)(left, right), and *add isn't the function, it's the first character of the code that add points to. (Right?)

I know that replacing the original definition of binary_op() with the following also works.

double binary_op(double left, double right, double f(double, double)) {
  return f(left, right);
}

And in fact, this makes much more sense to me, but the original syntax doesn't make sense as I explained above.

So, why is it syntactically correct to use (*f) instead of just f? If the symbol func is itself a pointer, then what precisely does the phrase "function pointer" or "pointer to a function" mean? As the original code currently stands, when we write double (*f)(double, double), what kind of thing is f then? A pointer to a pointer (because (*f) is itself a pointer to a bit of code)? Is the symbol add the same sort of thing as (*f), or the same sort of thing as f?

Now, if the answer to all of this is "Yeah C++ syntax is weird, just memorise function pointer syntax and don't question it.", then I'll reluctantly accept it, but I would really like a proper explanation of what I'm thinking wrong here.

I've read this question and I think I understand that, but haven't found it helpful in addressing my confusion. I've also read this question, which also didn't help because it doesn't directly address my type discrepancy problem. I could keep reading the sea of information on the internet to find my answer but hey, that's what Stack Overflow is for right?

like image 467
Ray Avatar asked Mar 06 '26 13:03

Ray


1 Answers

This is because C function pointer are special.

First of, the expression add will decay into a pointer. Just like reference to array will decay into a pointer, reference to function will decay into a pointer to function.

Then, the weird stuff it there:

return (*f)(left, right);

So, why is it syntactically correct to use (*f) instead of just f?

Both are valid, you can rewrite the code like this:

return f(left, right);

This is because the dereference operator will return the reference to the function, and both a reference to a function or a function pointer are considered callable.

The funny thing is that a function reference decay so easily that it will decay back into a pointer when calling the dereference operator, allowing to dereference the function as many time as you want:

return (*******f)(left, right); // ah! still works
like image 177
Guillaume Racicot Avatar answered Mar 08 '26 03:03

Guillaume Racicot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!