5

I am reading C++ in easy steps and came across a piece of code for references and pointers that I do not understand.

The code is void (* fn) (int& a, int* b) = add;. As far as I know it does not affect the program itself but would like to know what this code does.

#include <iostream>
using namespace std;

void add (int& a, int* b)
{
    cout << "Total: " << (a+ *b) << endl;
}

int main()
{
    int num = 100, sum = 200;
    int rNum = num;
    int* ptr = &num;

    void (* fn) (int& a, int* b) = add;

    cout << "reference: " << rNum << endl;
    cout << "pointer: " << *ptr << endl;

    ptr = &sum;
    cout << "pointer now: " << *ptr << endl;
    add(rNum, ptr);
    return 0;
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Sulaco-Lv223
  • 103
  • 1
  • 8
  • 1
    [Heres](http://cdecl.org/) a very good website for declarations. It's having trouble with this one, though. – yizzlez Aug 03 '15 at 13:58
  • This instruction assigns the variable `fn`, a pointer to function, the value of a pointer to the function `add`. `fn` isn't used later and the assignment is essentially useless. –  Aug 03 '15 at 14:01
  • @awesomeyi Because references aren't in C, and you can't name the arguments in declarations there either. – Barry Aug 03 '15 at 14:16

5 Answers5

11

Use the spiral rule:

     +----------------------+
     |  +--+                |
     |  ^  |                |
void (* fn ) (int& a, int* b) = add;
^    |     |                |
|    +-----+                |
+---------------------------+

fn is a pointer to a function taking two arguments (an int& named a and a int* named b) and returning void. The function pointer is copy initialized with the free function add.

So where in your code you have:

add(rNum, ptr);

That could be equivalently replaced by:

fn(rNum, ptr);
Barry
  • 286,269
  • 29
  • 621
  • 977
  • There is no assignment here and, even if there were, it would be `add` assigned to `fn` and not the other way around. – Lightness Races in Orbit Aug 03 '15 at 14:07
  • Right, flipped the words in my head. Fixed. – Barry Aug 03 '15 at 14:14
  • Perhaps [right-left rule](http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html) is better than spiral rule since [it can't handle](http://stackoverflow.com/q/16260417/183120) something as simple as `int *a[5][10]`? – legends2k Aug 03 '15 at 14:16
  • @legends2k Both rules suck and everybody should just use typedefs :) – Barry Aug 03 '15 at 14:22
  • Haha, that's true, using `typedef`s would be much better. However, once we're into the business of decrypting such declarations, which do turn up in the wild frequently, RL rule is preferred since it handles cases even the spiral rule fails to :) – legends2k Aug 03 '15 at 14:31
8

fn is a pointer to a function taking, from left to right, an int&, and an int*, that does not return anything.

You are assigning the function add to fn.

You could call the function add through the pointer, using exactly the same syntax as you would if you were use add.

One use of this technique is in the modelling of callback functions. For example, qsort requires a callback function for the sorting predicate. Function pointers are more common in C than in C++ where there are other techniques such as function objects, templates, lambdas, and even std::function.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
4

If you read about the clockwise/spiral rule the declaration is easy to decipher:

You declare a variable fn, which is a pointer, to a function, taking some arguments and returning nothing.

Then you make this function-pointer fn point to the add function.

You can then use the function-pointer instead of calling add directly.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
3

void (* fn) (int& a, int* b) = add; declares a function pointer named fn that points that points to a function that has a signature of void(int&,int*). it then intilizes the pointer to the add() function.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

Such complicated declarations are easily read using the right-left rule, which works even when the clockwise spiral rule fails, which does even in case of something as simple as int* a[][10].

void (* fn) (int& a, int* b);

Start with the identifier fn and go from right to left, with the parenthesis flipping the direction. So fn is a pointer to a function taking are reference to int and a pointer to int and the function's return type is void.

It's called reading boustrophedonically :) See this answer for another example.

Community
  • 1
  • 1
legends2k
  • 31,634
  • 25
  • 118
  • 222
  • [Right-Left Rule from Wayback](https://web.archive.org/web/20210523053011/https://cseweb.ucsd.edu/~ricko/rt_lt.rule.html) as original link is broken. – legends2k Apr 20 '22 at 09:41