3

I tried to use tempaltes as array dimension value. I was puzzled when tried to specify wrong dimension as tempate argument. For example code:

#include <iostream>

using namespace std;

template <int X, int Y>
void f(int a[X][Y]) {
    for (int i = 0; i < X; ++i) {
        for (int j = 0; j < Y; ++j) {
            cout << a[i][j] << " ";
        }
        cout << '\n';
    }
}

int main() {
    int a[2][2] = {{1, 2}, {3, 4}};
    f<2, 2>(a); // compilation succeeded
    f<10, 2>(a); // compilation succeeded
    f<2, 10>(a); // compilation FAILED
}

Why in the last case compilation fails, but in case <10, 2> it does not?

error: no matching function for call to 'f'
note: candidate function template not viable: no known conversion from 'int [2][2]' to 'int (*)[10]' for 1st argument
AndyG
  • 39,700
  • 8
  • 109
  • 143
spectator
  • 33
  • 3
  • 1
    Because of [array decay](https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay), the outer-most dimension can be a bit fuzzy, but all of the inner dimensions must be exact. – user4581301 Dec 10 '20 at 19:34
  • Note, this is why `std::vector` exists and why using multi-dimensional arrays as arguments is not a great plan. – tadman Dec 10 '20 at 19:35
  • Note that because there aren't 10 rows in that outer dimension in `f<10, 2>(a);`, `for (int i = 0; i < X; ++i)` will send the program out of bounds at runtime. – user4581301 Dec 10 '20 at 19:36
  • @tadman, yes, I know, it just for an experiment. – spectator Dec 10 '20 at 19:37

1 Answers1

6

You get this result because f(int a[X][Y]) is a lie.

Arrays are not first-class citizens in C++. You cannot pass an array as a function parameter by value. So when you write such parameter, it is silently adjusted to a pointer (the first level only). Thus the type of a is really int (*)[Y].

Since there is no X in the type of a, absolutely any X will work.

If you want to enforce both X and Y, try passing the array by reference:

void f(int (&a)[X][Y])

or use std::array.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Addendum This also ruins C++17's improved template argument inference. Without passing the array by reference as suggested in this answer, `f(a)` will infer a pointer to an array will miss out on the `X` argument. – user4581301 Dec 10 '20 at 19:40