#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!
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,print2()按预期工作,但print1()给我错误
错误:没有匹配函数来调用'print(int [4] [4])'
我不明白,它们看起来完全一样,我只是将硬编码值替换为使用模板,以便它可以接受任何大小的数组.
为什么不起作用?我究竟做错了什么?
Jam*_*lis 11
在宣言中
void print2(int src[4][4])
Run Code Online (Sandbox Code Playgroud)
第一个4是毫无意义的.此功能与您声明的功能相同
void print2(int src[][4])
Run Code Online (Sandbox Code Playgroud)
或者作为
void print2(int (*src)[4])
Run Code Online (Sandbox Code Playgroud)
这是因为数组永远不会通过C和C++中的值传递.相反,当一个数组传递给一个函数时,它会被隐式转换为指向其初始元素的指针.同样,当函数参数的类型为"array of T"时,它会自动转换为"指向T" 的类型.实际上,C和C++中没有数组类型参数.
那么,让我们考虑一下你的功能模板:
template <int M, int N>
void print1(int src[M][N])
Run Code Online (Sandbox Code Playgroud)
与print2此类似,此函数模板相当于:
template <int M, int N>
void print1(int src[][N])
Run Code Online (Sandbox Code Playgroud)
为了在没有明确声明调用中的模板参数的情况下调用此函数,编译器必须能够推断出参数类型的内容M和N来源. M并没有真正出现在参数列表中的任何位置,因此无法从参数中推断出它.您可以通过在进行调用时显式提供模板参数来调用此函数:
print1<4, 4>(src)
Run Code Online (Sandbox Code Playgroud)
然而,正如我们上面所看到的,编译器可以推断N自己; 只是M它不能推断出来.因此,您也可以通过仅为M编译器提供参数并让编译器推断来进行调用N:
print1<4>(src)
Run Code Online (Sandbox Code Playgroud)
或者,您可以将函数模板声明为引用数组:
template <int M, int N>
void print1(int (&src)[M][N])
Run Code Online (Sandbox Code Playgroud)
这抑制了数组到指针的转换.为什么?请记住,在前面的示例中,参数是"指向一维数组的指针int".但是,在此函数模板中,参数是"对二维数组的引用int".两个范围(维度)都是类型的一部分,因此两者都可以由编译器推导出来.
但是,在大多数情况下,最好避免多维数组和对数组的引用,因为它们很麻烦.这两种方法都不适用于动态分配,并且保持数组到指针转换不会发生很多麻烦.
使用此语法来声明模板函数:
template <int M, int N>
void print1(int (&src)[M][N])
{
}
Run Code Online (Sandbox Code Playgroud)