Это потому, что когда вы передаете массив «по значению», он распадается на указатель. То есть вы фактически передаете указатель на первый элемент без информации о размере.
Когда у вас есть такая подпись:
void foo(int arr[10]);
, тогда значение 10 полностью игнорируется, и вы можете передавать ему массивы целых чисел любого размера. Это точно так же, как
void foo(int arr[]);
или
void foo(int* arr);
Как видите, информация о размере не сохраняется, и поэтому ее нельзя использовать для определения размера массива.
При двумерном массиве первое измерение затухает. Например: массив из 10 массивов из 20 целых чисел (int arr[10][20]
) распадается на указатель на массивы из 20 целых чисел (int (*arr)[20]
) и т. Д., Поэтому значение 10 не может быть выведено, но размер второго измерения (20) равен может быть выведен.
template<class T,int row, int col>
void foo(T (&a)[row][col]) { }
template <class T, int col>
void bar(T arr[][col]) {}
int main()
{
int a[10][20];
foo(a);
bar(a);
}
Когда вы передаете что-либо по ссылке, тип сохраняется, массивы не исчезают, и вся информация о размере остается доступной.