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