2

From here: https://stackoverflow.com/a/3473454/499125

int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
    return arr;
}

The definition above can force the compiler to become size-aware of its parameters. This statement seems complex to me. Can someone give an anatomy of this statement or explain how does the statement achieves the size-awareness?

Can this be extended to handle multiple parameters?

Community
  • 1
  • 1
Some Noob Student
  • 14,186
  • 13
  • 65
  • 103
  • That function *returns* a reference to an `int[5]`, which doesn't seem to be what you need or want. – Kerrek SB Aug 20 '12 at 16:08
  • 2
    fillar is a function taking one parameter of type reference to an array of five `int`s, returning a reference to an array of five `int`s. – jrok Aug 20 '12 at 16:09
  • So, what do you want to achieve? – Lol4t0 Aug 20 '12 at 16:12
  • 4
    It can be extended: `int ( &fillarr( int (&arr1)[5], int (&arr2)[5] ) )[5] { }` But please, use vectors or `std::array` instead. – jrok Aug 20 '12 at 16:15

2 Answers2

8

It all boils down to being able to read the declaration. A simpler way of writing exactly the same would be:

typedef int int5[5]; // create a typedef
int5& fillarr( int5& ) {
}

As of the exact way of reading the original declaration, just break it into pieces:

int (&fillarr( int (&arr)[5] ))[ 5 ];
               ^^^^^^^^^^^^^           // A: reference to array of 5 int
^^^^^^                        ^^^^^^   // B: reference to array of 5 int
      ^^^^^^^^               ^         // C: function taking A and returning B
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • wait, what's that [5] doing _behind_ int5? Does this turn all `int5` into `int _sth_ [5]`? Such as `int5 &` -> `int & [5]` ? – Some Noob Student Aug 20 '12 at 16:31
  • 1
    @SomeNoobStudent: This is the *joy* of C style type declarations. In the same way that `int arr[5];` declares an *array of 5 int*, `typedef int int5[5];` creates a type alias that represents an *array of 5 int*. What is `[5]` doing *behind* the name? That is how declarations go in the language. – David Rodríguez - dribeas Aug 20 '12 at 16:35
2

You can split understanding this in two parts, 1) the return value and 2) the parameter type:

int ( &fillarr() )[5] {
  static int arr[5];
  return arr;
}

We can have a look at the type: int (&fillarr())[5]. To understand this, unfortunately the old C rule: "Declaration is like usage in expressions" doesn't work with references, so let's have a look at a similar declaration instead:

int (*fillarr())[5];

This is a function that returns a pointer instead of a reference to an array of size 5. How do I figure? Well, assume we do have a function f that returns a pointer to an array of ints, how would we access the fifth element? Let's see, we first have to call the function: f(). Then we have to dereference the result *f() and then access the fifth element (which doesn't exist, but ignore that) (*f())[5] which is an int. This is exactly the declaration syntax:

int x;
int (*f())[5];
x = (*f())[5];
//    ^^^-------- call f -> yields pointer to array of 5 ints
//   ^----------- dereferene the result of f -> yields array of 5 ints
//        ^^^---- access the fifth element

Now you only substitute the * for an & because you're returning a reference in your example.

The parameter syntax works analogously.

bitmask
  • 32,434
  • 14
  • 99
  • 159