#include <iostream>
template <int M, int N>
void print1(int src[M][N]) { }
void print2(int src[4][4]) { }
int main() {
int src[][4] = {
{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9, 10, 11, 12},
{13, 14, 15, 16},
};
print1(src);
// gives error
// error: no matching function for call to 'print1(int [4][4])'
print2(src);
// works!
}
In code above, print2() works as expected, but print1() gives me the error
error: no matching function for call to ‘print(int [4][4])’
I don’t understand, they look exactly the same, I just replaced the hard coded values to use templates so that it can accept arrays of any size.
Why does it not work? What am I doing wrong?
In the declaration
The first
4is meaningless. This function is the same as if you had declared it asor as
This is because arrays are never passed by value in C and C++. Rather, when an array is passed to a function, it is implicitly converted to a pointer to its initial element. Likewise, when a function parameter has the type “array of
T“, it is transformed automatically to be of type “pointer toT.” In effect, there are no array type parameters in C and C++.So, let’s consider your function template:
Similar to
print2, this function template is equivalent to:In order to call this function without explicitly stating the template arguments in the call, the compiler must be able to deduce what
MandNare from the type of the argument.Mdoesn’t really appear anywhere in the argument list, so there’s no way for it to be deduced from the argument. You could call this function by explicitly providing the template arguments when you make the call:As we saw above, however, the compiler can deduce
Nitself; it’s justMthat it can’t deduce. Therefore, you can also make the call by only providing an argument forMand letting the compiler deduceN:Alternatively, you could declare the function template as taking a reference to an array:
This suppresses the array-to-pointer conversion. Why? Remember that in the previous examples, the parameter was “a pointer to a single-dimensional array of
int.” However, in this function template, the parameter is “a reference to a two-dimensional array ofint.” Both extents (dimensions) are part of the type, and therefore both can be deduced by the compiler.However, in most cases it is best to avoid multidimensional arrays and references to arrays because they are cumbersome. Neither works well with dynamic allocation, and it’s often a lot of trouble to keep the array-to-pointer conversion from occurring.