此 C++ 代码是什么意思?

What does this C++ code mean?

提问人:Luchian Grigore 提问时间:11/1/2011 更新时间:11/26/2011 访问量:1104

问:

以下代码返回堆栈分配的数组的大小:

template<typename T, int size>
int siz(T (&) [size])
{
    return size;
}

但我无法理解语法。 尤其是那部分......T (&) [size]

C++ 模板

评论

1赞 sharptooth 11/1/2011
为什么在 C++ 中以如此令人困惑的方式定义“对数组的引用”
7赞 Jason S 11/1/2011
不完全是重复的
0赞 Johannes Schaub - litb 11/27/2011
您可能希望使用别名模板并编写可能更易于阅读的模板。alias<T[size]> &

答:

24赞 Maxim Egorushkin 11/1/2011 #1

但我无法理解语法。尤其是那部分......T (&) [size]

该部分是对数组的引用。有“左右规则”用于破译任何 C 和 C++ 声明。

由于函数模板从提供的函数参数中推断模板参数类型,因此此函数模板的作用是推断数组的类型和元素计数并返回计数。

函数不能按值接受数组类型,而只能按指针或引用接受数组类型。引用用于避免数组到指向其第一个元素的指针的隐式转换(也称为数组衰减):

void foo(int*);

int x[10];
int* p = x; // array decay
foo(x);     // array decay again

数组衰减会破坏数组的原始类型,因此它的大小会丢失。

请注意,因为它是 C++03 中的函数调用,所以返回值不是编译时常量(即返回值不能用作模板参数)。在 C++11 中,可以标记函数以返回编译时常量:constexpr

template<typename T, size_t size>
constexpr size_t siz(T(&)[size]) { return size; }

要在 C++03 中将数组元素计数作为编译时常量,可以使用略有不同的形式:

template<class T, size_t size>
char(&siz(T(&)[size]))[size]; // no definition required

int main()
{
    int x[10];
    cout << sizeof siz(x) << '\n';
    double y[sizeof siz(x)]; // use as a compile time constant 10
}

在上面,它声明了一个函数模板,该模板具有相同的数组引用参数,但返回值类型为 (这是可以理解“左右规则”的地方)。请注意,函数调用永远不会在运行时发生,这就是为什么不需要定义函数模板的原因。 基本上是说“如果调用 siz(x),返回值的大小是多少”。char(&)[size]sizsizeof siz(x)

获取数组元素计数作为编译时常量的旧 C/C++ 方法是:

#define SIZ(arr) (sizeof(arr) / sizeof(*(arr)))

评论

0赞 Jason S 11/1/2011
& 周围的 parens 是必要的吗?
0赞 Flexo 11/1/2011
@JasonS - 需要 parens 以避免看起来像对T
0赞 Jason S 11/1/2011
啊,好吧。。。而且也行不通?(对不起,没有启动并运行 C 编译器)(T&)[size]
1赞 Flexo 11/1/2011
@JasonS 不,这和 .括号清楚地表明 不是指构成数组元素的类型。(不过,C 编译器对测试它没有多大好处 - C 中没有引用!T&&
1赞 Jason S 11/3/2011
@awoodland:啊!灯终于亮了。所以引用 T 数组而不是引用数组。
4赞 MäxL 11/1/2011 #2

这是一个函数,它变成了一个类型名(模板可以与不同的类型名一起使用)和外部的大小。然后,它返回此大小。

堆栈函数通常使用 ,这是一个整数,显示使用此函数请求的堆栈大小的大小。测试堆栈 T 的大小。size&

7赞 Flexo 11/1/2011 #3

T (&) [size]是对数组的引用。它需要作为参考,因为以下程序是不合法的:

#include <iostream>

int sz(int *) { std::cout << "wtf?" << std::endl; return 0; }


int sz(int [4]) { std::cout << "4" << std::endl; return 0; }

int main() {
  int test[4];
  sz(test);
}

此程序无法编译:

test.cc: In function ‘int sz(int*)’:
test.cc:6:5: error: redefinition of ‘int sz(int*)’
test.cc:3:5: error: ‘int sz(int*)’ previously defined here

因为等同于 .int sz(int [4])int sz(int *)

这里需要括号来消除歧义,因为看起来像一个引用数组,否则是非法的。T& [size]

通常,如果参数不是匿名的,你会写:

template<typename T, int size>
int sz(T (&arr) [size])

为数组指定名称 。但是,在本例中,您的示例代码所关心的只是推断出的大小,因此匿名参数避免了有关未使用参数的警告。arr