I have been brushing up on array concepts in C++, when I came across this question: Return an array in c++
Someone answered using this declaration:
int (&f(int (&arr)[3]))[3]
What I can't seem to grasp is the [3] after the closing parenthesise. I've never seen a function declaration that looked like this. I understand the rest of the syntax, but I don't particularly understand how the [3] works because it is after the function name. I apologize in advance if I'm overlooking something simple. I also tried looking at the spec for function declarations but I didn't see anything related that I could link to the subscript syntax. So, how is this possible?
The function is returning a reference to an array of int of size 3 and the [3] part after the function actually the size of the array to be returned as reference.
This obscure syntax comes from the weird syntax of array declaration, which you do as:
int arr[3]; //real but weird
The language would have been much simpler if it had this instead:
int[3] arr; //hypothetical but better and simpler
because size 3 is part of the type of arr, so it makes much more sense if all the parts appear on the left side of the variable name, in the same way as when you write:
unsigned int a;
You dont write:
unsigned a int; //analogous to : int a [3];
So while the language does the right thing with unsigned int, it does a very weird thing with int[3].
Now coming back to the function declaration, the function would have been much better if it is declared as:
int[3]& f(int[3]& arr); //hypothetical
only if it had all the parts on the left side of variable-name. But since it doesn't do that (i.e the language requires you to write the size on the rightmost side after the variable name), you end up with this weird signature:
int (&f(int (&arr)[3])[3]; //real
Notice that how even the parameter becomes weird.
But you can simplify it with a typedef as:
typedef int array_type[3];
array_type& f(array_type& arr);
That looks much better. Now only the typedef looks weird.
With C++11, you can write even a better typedef:
using array_type = int[3];
array_type& f(array_type& arr);
which is as close as this (if you visualize array_type as int[3]):
int[3]& f(int[3]& arr); //hypothetical
Hope that helps.
Well, read this article about C history, by its creator Dennis M. Ritchie.
Looks like this syntax we got from B, thru C to C++...
I believe, this way of declaring several variables of some "basic type" is a root of this strange syntax:
int a, *b, c[3];
So a is just int, b is pointer to int and c is array of int...
If these * and [3] would be part of type definition not a variable definition - then we would need 3 lines to write this:
int a;
int* b;
int[3] c;
There are two good resources on SO C page to learn how to parse such constructions:
cdecl is failing a little - because references are not part of C - so let's try with The Clockwise/Spiral Rule for parsing C declarations.
int (&f(int (&arr)[3]))[3]
arr -> arr &arr -> arr is reference (&arr) -> arr is reference - surrounding () not really change a thing(&arr)[3] -> arr is reference to array of size 3 int (&arr)[3] -> arr is reference to array of size 3 of type intNext:
f -> f f(int (&arr)[3]) -> f is function taking arr, which is ...&f(int (&arr)[3]) -> f is function taking arr, which is ..., and returning reference(&f(int (&arr)[3]))[3] -> f is function taking arr, which is ..., and returning reference to array of size 3int (&f(int (&arr)[3]))[3] -> f is function taking arr, which is reference to array of size 3 of type int, and returning reference to array of size 3 of type intOf course - this code shall be replaced with, at least for me, much easier to read version:
using int3 = int[3];
int3& f(int3& arr);
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With