7

What would typedef int (&rifii) (int, int) be used for?

What is the typedef before this "statement" do? I want to think of this as

typedef (int (&rifii) (int, int)) [new name]

but the [new name] is not there like if you do

typedef int INTEGER;

Similar question for the following syntax:

typedef void (*PF) ();

PF edit_ops[ ] = { &cut, &paste, &copy, &search };
PF file_ops[ ] = { &open, &append, & close, &write };

PF* button2 = edit_ops;
PF* button3 = file_ops;

button2[2]( );

What is the typedef allowing? Is it making it so you don't have to type:

void (*PF) ();
(void (*PF) ()) edit_ops[ ] = { &cut, &paste, &copy, &search };
(void (*PF) ()) file_ops[ ] = { &open, &append, & close, &write };

(void (*PF) ())* button2 = edit_ops;
(void (*PF) ())* button3 = file_ops;

If so what happend to the second part ([what you want]) of the typedef like in:

typedef [what you have -- (FP)] [what you want]

Clarification on this matter is greatly appreciated.

Matthew Hoggan
  • 7,402
  • 16
  • 75
  • 140
  • a possible duplicate of http://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c-examples-hints-and-tips-plea – vines Aug 01 '11 at 23:41
  • The question is similar, and I did look through the related topics before posting, however my question was specific and I was not able to extrapolate an answer from the other posts. – Matthew Hoggan Aug 01 '11 at 23:47

2 Answers2

17

Typedef does not work like typedef [type] [new name]. The [new name] part does not always come at the end.

You should look at it this way: if [some declaration] declares a variable, typedef [same declaration] would define a type.

E.g.:

  • int x; declares a variable named x of type int -> typedef int x; defines a type x as int.
  • struct { char c; } s; defines a variable named s of some struct type -> typedef struct { char c; } s; defines type s to be some struct type.
  • int *p; declares a variable named p of type pointer to int -> typedef int *p; defines a type p as pointer to int.

And also:

  • int A[]; declares an array of ints named A -> typedef int A[]; declares a type A as an array of ints.
  • int f(); declares a function named f -> typedef int f(); declares a function type f as returning an int and taking no arguments.
  • int g(int); declares a function name g -> typedef int g(int); declares a function type g as returning an int and taking one int.

As an aside: Note that all function arguments come after the new name! As those types could be complicated as well, there can be a lot of text after the [new name]. Sadly, but true.

But those are not proper function pointers yet, just function types. I'm not sure a function type exists in C or C++, but it is useful as an intermediate step in my explanation.

To create a real function pointer, we have to add '*' to the name. Which, sadly, has wrong precedence:

  • typedef int *pf(); declares a function type pf as return a int*. Oops, that's not what was intended.

So use () to group:

  • typedef int (*pf)(); declares a function pointer type pf as returning an int and taking no arguments.
  • typedef int (&rf)(); declares a function reference type rf as returning an int and taking no arguments.

Let's now look at your examples and answer your questions:

typedef int (&rifii) (int, int); declares a function reference type rifii as returning an int and taking two int arguments.

And obviously (?) button2[2]( ); will call copy();.

Proper syntax without typedefs is hard to write correctly without a compiler, and hard to read even with a compiler:

void (*edit_ops[])() = { &cut, &paste, &copy, &search }; 
void (*file_ops[])() = { &open, &append, & close, &write };

void (**button2)() = edit_ops;
void (**button3)() = file_ops;

button2[2]( );   

Which is why everyone prefers typedefs when using function pointers.

When reading, find the place to start reading. Read as much to the right as you can, but observe the grouping by (). Then read to the left as much as you can, again limited by grouping (). After finishing everything inside the (), start with reading to the right, then to the left.

Applied to void (*edit_ops[])(), this means that

  1. edit_ops is (go to the right)
  2. an array (hit the end of the group, so turn to the left)
  3. of pointer (end of grouping)
  4. to a function taking (parse the () to the right)
  5. no arguments (go to the left)
  6. returning a void

For the experts: To make it even more complicated, arguments can have names (which will be ignored), so it might even be hard to find where to start parsing! E.g. typedef int (*fp)(int x); is valid and the same as typedef int (*fp)(int); Names can even have () around them: typedef int (*fp)(int (x)); But as we have seen, argument names can be left out, so even the following is allowed: typedef int (*fp)(int ());. This is still a function pointer taking a single int and return an int. In case you would like to make your code really hard to read...

Sjoerd
  • 6,837
  • 31
  • 44
  • Your explanation is helping. For clarification: typedef void (*PF) (); declares a type (*PF) which is defined as a function pointer that takes 0 arguments and returns nothing. So now that we have a type PF if we can use that in our expressions (i might mean statements) such as PF edit_ops[] = {...}. Without defining the "new type" we use void (*edit_ops[])( ) = {...}. This says we are creating an array of function pointers which can be one of the ...? The type of this expression is a function pointer? – Matthew Hoggan Aug 02 '11 at 01:06
  • @Matthew: Yes, `void (*edit_ops[]() = { ... };` is defining an array of function pointers, and initializes this array with the values `cut`, `paste`, `copy`, and `search`. `void (**button2)() = edit_ops;` declares a pointer to the zero-th element of that array. `button2[2]( );` uses the third element of the array and calls the function it points to. Which happens to be `copy`. – Sjoerd Aug 02 '11 at 01:21
  • @Matthew: In your first sentence, `typedef void(*PF)()` declares a type `PF`, *not* `(*PF)`. `PF` is already a pointer. The last statement `void(*x[])() = ...` declares `x` to be an array of function pointers. – Kerrek SB Aug 02 '11 at 01:24
-1

edit: sorry first answer didn't initialize the fcn ptr.

typedef int (&rifii) (int, int) allows you to declare function pointers that return an int by reference and take two ints as parameters.

    rifi x,y,z;

int &ret_an_int_ref( int p1, int p2 ) { 
    static int retval=0;
    if( p1 > p2 ) retval = p1*p2;
    return retval;
}

    x = ret_an_int_ref;
    y = ret_an_int_ref;

int & an_int_ref = x(1,2);
int & another_int_ref=y(3,4);

z = x;

z(1,2); // will give the same answer as x(1,2);
Harry Seward
  • 147
  • 1
  • So rifi is now a type? And the variables x,y,and z are of that type? And according to Bjarne, returning a reference from a function is a sin, so I am assuming I will never see this? – Matthew Hoggan Aug 01 '11 at 23:43
  • I cannot say with 100% certainty if rifi is a "type", hopefully a guru can chime in. It acts just like a type, can be passed around like a type, and probably used as a template parameter. You will most likely never see this, however sometimes for complex data types it's better to return by ref. And operator= should always return by ref, so that dumb statements like A=A don't cause a seg fault. – Harry Seward Aug 01 '11 at 23:46
  • 1
    The function does not return a reference to int, but it is a reference to a function returning a (plain) int. Your version would have been `typedef int &(rifii)(int,int);` – Sjoerd Aug 01 '11 at 23:52
  • oops, sorry for posting bad info :( – Harry Seward Aug 02 '11 at 16:14