参数printArray(int(&a)[n] [m])是什么意思?为什么必须使用括号,为什么只需要为printArray函数提供1个值?调用时函数如何知道n和m?
template <size_t n, size_t m>
void printArray(int (&a)[n][m]) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << a[i][j] << " ";
}
cout << endl;
}
}
int main(int argc, char* argv[])
{
cout << "Example I:" << endl;
int ab[2][5];
printArray(ab);
cout << "Example II:" << endl;
int b[2][5] = {{1, 2, 3}};
printArray(b);
cout << "Example III:"<< endl;
int c[][5] = {1, 2, 3, 4, 5, 6, 7};
printArray(c);
cout << "Example IV:" << endl;
int d[][5] = {{1, 2, 3, 4}, {5, 6}, {7}};
printArray(d);
}
参数
printArray(int (&a)[n][m])
是什么意思?
这意味着a
是对int[n][m]
类型的对象的引用。 int[n][m]
是m
类型的int[n]
对象的数组。 int[n]
是n
类型的int
对象的数组。因此,a
是对尺寸为n
和m
的二维数组的引用。
n
和m
是在template <size_t n, size_t m>
中宣布的模板参数。两个参数的类型是size_t
,它是一个整数类型。
为什么括号必要
因为&-token绑定到左边。 int&
是对int的引用。 int& a[n]
在语法上意味着a
是一个引用数组(尽管不允许这样的数组)。括号用于消除&-token是否声明对int的引用(数组)或对数组的引用的歧义。
为什么只需要为printArray函数提供1个值?
该函数只有一个参数:a
。如果传递一个可以绑定到适当类型的数组引用的值,那么它可以工作。在所有示例中,参数都是2d整数数组,因此它们是正确的。
调用时函数如何知道n和m?
编译器知道,因为数组的大小是数组类型的一部分。并且因为模板参数演绎。如果未明确指定模板参数,则可以从函数的参数中推断出它。在这种情况下,如果传递int[2][5]
类型的参数,则n
推导为2,m
推导为5。
您甚至可以添加模板类型参数,并推导出它:
template <size_t n, size_t m, typename T>
void printArray(T (&a)[n][m])
T
将被推断为int
,如果你要传递2d整数数组。
如果不允许引用数组,为什么编译器不能推断出括号不是必需的。
如果int &a[n]
意味着对数组的引用,因为不能有引用数组,那么程序员会混淆int *a[n]
不是指向数组的指针,因为可能存在指针数组。
此外,通过为不必要的引用添加特殊情况,这会使语言复杂化。
为什么不是形式:printArray(int [n] [m]&a)
更简单的说,为什么int[n] a
而不是int a[n]
不能声明数组。因为后者的语法是由(大概是Dennis Ritchie,他是)C语言的设计者选择的。
它只是通过引用获取数组。只要传递的数组的使用进入函数内部,您通常会编写完全相同的代码。唯一的区别是它保留了它的数组类型。
当你将数组“按值”传递给一个函数时,它实际上已经衰变为指向它的第一个元素的指针。通过引用(或通过地址)传递它可以防止此用法中的这种衰减。
实际上,即使您为参数中的第一个维度指定了范围,如果数组是“按值”传递,编译器也会忽略它。
这是一个模板编程技巧,可以推断出第一个维度的范围,否则如果您写了以下内容则会丢失:
template<size_t m>
void printArray(int a[][m]) {...}
因此,替代方案可能不那么整洁:
template<size_t m>
void printArray(int a[][m], size_t n) {...}
括号是必需的,因为int &a[n][m]
是一个2D引用数组,这是非法的,因为你不能创建一个引用数组。 int (&a)[n][m]
中的括号使这个“引用nxm数组的int”。