1

参考。在我的一篇文章和sellibitze 对该文章的评论中通过引用而不是值传递数组时,为什么当我通过值传递数组时编译器可以推断参数但如果我通过值传递它就不会这样做?

template<class T,int row, int col>
void invert(T (&a)[row][col]) //NOTE AMPERSAND

在上面的声明中,我可以调用:

int main(int argc, char* argv[])
{
invert(a);//HERE ARGUMETS ARE AUTOMATICALLY DEDUCED
}

但如果没有&符号,我将不得不这样称呼它:

 int main(int argc, char* argv[])
    {
    invert<int,3,4>(a);
    }

@Paul所以只是为了在我声明fnc时说清楚:

void f(int a[]);//I'm passing a pointer

但是当我声明时:

void f(int &a[]);//I'm passing a ref?

我现在理解正确了吗?

4

3 回答 3

3

那是因为当你“按值”传递一个数组时,它会衰减为一个指针。也就是说,您实际上是在传递一个指向第一个元素的指针,而没有任何大小信息。

当你有这样的签名时:

 void foo(int arr[10]);

那么值 10 将被完全忽略,您可以将任何大小的整数数组传递给它。它与

 void foo(int arr[]);

或者

void foo(int* arr);

如您所见,未保留大小信息,因此它不能用于推断数组的大小。

对于二维数组,第一个维度会衰减。例如:一个由 20 个整数组成的 10 个数组的数组 ( 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);
}

当您通过引用传递某些内容时,类型会被保留,数组不会衰减,并且所有大小信息都将保持可用。

于 2010-04-02T11:14:28.410 回答
1

您不能按值传递数组,只能通过指针传递(当您将数组传递给函数时,它会自动转换为指针)。

我不太明白您所说的“推断论点”是什么意思;你的意思是数组的总大小?如果是,那么如果你通过指针传递它,它就会丢失,因为指针不携带那种信息。

无论如何,我强烈建议使用std::vector而不是普通的旧 C 数组;少了很多头痛!默认情况下,它们是按值传递的(如您所料);如果您愿意,它们可以通过引用和指针轻松传递,并且它们永远不会丢失诸如数组大小之类的信息。它们还可以防止缓冲区溢出和下溢,并且它们会随着您添加更多元素而自动增长。

于 2010-04-02T10:48:21.723 回答
1
void f(int &a[]); // I'm passing a ref?

不,在这里您尝试传递类型系统中不存在的引用数组。您可能很想写以下内容:

void f(int (&a)[]);

但是对于未知范围的数组的引用不允许作为函数参数。


当您将函数参数声明为 n 维数组时,编译器会将其重写为指向 n-1 维数组的指针。以下签名是等效的:

void fun(int x[][10]);
void fun(int x[2][10]);
void fun(int x[99][10]);
void fun(int (*x)[10]);

第一个维度的界限被忽略,因此无法通过模板机制推断。

你可以做的是传递一个指向整个二维数组的指针:

template <class T, int row, int col>
void invert(T (*a)[row][col])
{
    std::cout << row << " x " << col << std::endl;
    T first_entry = (*a)[0][0];
}

int main(int argc, char* argv[])
{
    int a[10][20];
    invert(&a);
}

这可以按预期工作,但正如您所见,双方的语法都有点笨拙。

于 2010-04-02T11:14:13.450 回答