在函数中引用数组和数组作为参数有什么区别?

Whats the difference between reference to an array and array as a parameters in functions?

提问人:hgrev 提问时间:12/18/2021 最后编辑:Vlad from Moscowhgrev 更新时间:12/18/2021 访问量:316

问:

引用数组的函数之间有什么区别:

// reference to array
void f_(char (&t)[5]) {
    auto t2 = t;
}

简单地说:

// just array
void f__(char t[5]) {
    auto t2 = t;
}

作为参数?

调用代码为:

char cArray[] = "TEST";
f_(cArray);
f__(cArray);

char (&rcArr)[5] = cArray;
f_(rcArr);
f__(rcArr);

在这两种情况下,t2 都是 char*,但在第一个函数中,我的 VS2019 显示 t 内部函数的类型为 char(&t)[],而第二个函数内部的 t 类型为 char*。

那么,这些功能之间到底有什么实际区别吗?

C++ C++11 按引用传递 隐式转换

评论

0赞 molbdnilo 12/18/2021
尝试将数组作为参数传递给两个函数,并看到第一个函数失败。(第二个实际上需要一个指针,而不是一个数组。
0赞 hgrev 12/18/2021
我编辑了这个问题。函数采用精确大小的数组。
2赞 molbdnilo 12/18/2021
第二个仍然需要指针;如果没有引用,则忽略大小。
0赞 Pete Becker 12/18/2021
事实上,第二个并没有采用精确大小的数组。它需要一个指针。试试吧!
1赞 Pete Becker 12/18/2021
这并不能解决问题,但包含两个连续下划线 () 的名称和以下划线后跟大写字母开头的名称将保留供实现使用。不要在代码中使用它们。f__

答:

2赞 Vlad from Moscow 12/18/2021 #1

例如,您可以指定一个完整的数组类型参数

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

在函数中,您将知道传递的数组中的元素数。

当函数声明为

void f( int a[] );

然后编译器调整函数声明,如下所示

void f( int *a );

并且您无法确定传递的数组中的元素数。因此,您需要指定第二个参数,例如

void f( int *a, size_t n );

此外,具有引用数组参数类型的函数可能会重载。例如,这两个声明

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

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

声明两个不同的函数。

具有引用数组参数类型的函数可以使用带支撑的列表(前提是相应的参数具有限定符 const)调用,例如

f( { 1, 2, 3 } );

这是一个演示程序

#include <iostream>

void f( const int ( &a )[] )
{
    std::cout << "void f( const int ( & )[] ) called.\n";
}

void f( const int ( &a )[2] )
{
    std::cout << "void f( const int ( & )[2] ) called.\n";
}

void f( const int a[] )
{
    std::cout << "void f( const int [] ) called.\n";
}


int main()
{
    f( { 1, 2, 3 } );
}

程序输出为

void f( const int ( & )[] ) called.

评论

0赞 hgrev 12/18/2021
谢谢,但第一个示例无法编译。您需要指定size_t参数如下: template<size_t N> void f(int (&a)[N]) {};
0赞 Vlad from Moscow 12/18/2021
@hgrev 我不是说模板函数。我的意思是非临时函数。N 是某种常量表达式或不存在常量表达式。
0赞 hgrev 12/18/2021
是的,我的意思是非模板函数,但在您指定 N 之前它不会编译
0赞 Vlad from Moscow 12/18/2021
@hgrev 您似乎正在使用旧的编译器或包含错误的编译器。请参阅我更新的帖子。您可以在 www.godbolt.org 试用该程序
1赞 Vlad from Moscow 12/18/2021
@hgrev 如果参数中的元素数指定为例如 void f( int ( &a )[10] );然后你就会知道这个数字了:) 您可以将运算符 sizeof 应用于参数,您将获得数组的确切大小。当参数没有引用类型时,即使您指定 void f( int a[10] );编译器会调整函数声明,如 void f( int *a );也就是说,您将处理一个指针。
0赞 Chris Dodd 12/18/2021 #2

由于不能按值传递数组(C++ 继承的 C 限制),因此任何将参数声明为数组都将“衰减”为指针(失去其大小)。所以宣言

void f__(char t[5])

等同于

void f__(char *t)

其他所有内容都由此而来 -- 在 的主体中,有一个指针类型,而不是数组类型。因此,从它进行的任何推断都将基于该指针类型。f__tauto