0

Followup to Range-for-statement cannot build range expression with array function parameter.

The original error is:

error: cannot build range expression with array function parameter 'arr' since parameter with array type 'int []' is treated as pointer type 'int *'

The failing code:

void print(int (&arr)[int]){
    for(int x: arr)
        cout<<" "<<x;
    cout<<endl;
}

The fixed code:

template<int N>
void print(int (&arr)[N]){
    for(int x: arr)
        cout<<" "<<x;
    cout<<endl;
}

My question is, why do we have to fix it like this? I do not understand what int (&arr)[int] means.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Lusha Li
  • 319
  • 3
  • 11

2 Answers2

0

Your question is a little confusing because your first example is not valid code.

However, I think there is still an explanation to provide here. Here's a "correct" version of your first function:

void print(int (&arr)[5]){
    for(int x: arr)
        cout<<" "<<x;
    cout<<endl;
}

void foo() {
    int x[5];
    int y[3];

    print(x);
    print(y); // Bam! error!
}

The print() function takes an array of 5 ints as a parameter. Note that this can only be done with statically sized arrays. The compiler must know the size of the array when compiling the function, and that function will only work for that particular array size.

Let's contrast that with your second, valid example.

A single array size, that's kind of annoying. What if I don't want to write a different function for various array sizes? We could always pass a pointer and a size, but that's kind of ugly (not to mention error prone).

Instead, we can give the compiler a function template. That is, not a function, but a recipe on how to create functions on-demand.

template<int N>
void print(int (&arr)[N]){
    for(int x: arr)
        cout<<" "<<x;
    cout<<endl;
}

The constant 5 has been replaced by the placeholder constant N (which will have to be an int, as specified in the template declaration. This way, the compiler will generate a separate print() function for each array size we call it with.

  • Do you mean if we declare a function with an array as an input we have to specify the array size since the compiler have to know the array size? Is it also because array is not dynamically sized? – Lusha Li May 31 '18 at 19:00
  • @LushaLi "specify the array size since the compiler have to know the array size?" Yes-ish. In order to use the range-based `for` loop, the compiler needs to know the size in order to know where to stop. "Is it also because array is not dynamically sized?" No. Dynamic allocation would actually make this worse because there is no way to infer the size of an array from a pointer. The real problem is the array decays to a pointer when passed into a function. More on that here: [What is array decaying?](https://stackoverflow.com/questions/1461432/what-is-array-decaying) – user4581301 May 31 '18 at 19:27
0

The rationale behind that is that C++ only allows constepr for array dimensions. The template version ensures that N is a constepr (a compile time constant) while the incorrect one let think that you intend to use a run time integer value for the array size - which is unfortunately forbidden in C++

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252