这个C++代码是什么意思?

Luc*_*ore 22 c++ templates

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

template<typename T, int size>
int siz(T (&) [size])
{
    return size;
}
Run Code Online (Sandbox Code Playgroud)

但我无法理解语法.特别是T (&) [size]部分......

Max*_*kin 24

但我无法理解语法.特别是T (&) [size]部分......

该部分是对数组的引用.有解释任何C和C++声明的"左右规则".

因为函数模板从提供的函数参数中推导出模板参数类型,所以此函数模板所做的是推导出数组的类型和元素数并返回计数.

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

void foo(int*);

int x[10];
int* p = x; // array decay
foo(x);     // array decay again
Run Code Online (Sandbox Code Playgroud)

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

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

template<typename T, size_t size>
constexpr size_t siz(T(&)[size]) { return size; }
Run Code Online (Sandbox Code Playgroud)

要在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
}
Run Code Online (Sandbox Code Playgroud)

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

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

#define SIZ(arr) (sizeof(arr) / sizeof(*(arr)))
Run Code Online (Sandbox Code Playgroud)


Fle*_*exo 7

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);
}
Run Code Online (Sandbox Code Playgroud)

该程序无法编译:

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
Run Code Online (Sandbox Code Playgroud)

因为int sz(int [4])是相同的int sz(int *).

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

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

template<typename T, int size>
int sz(T (&arr) [size])
Run Code Online (Sandbox Code Playgroud)

给数组命名arr.在这种情况下,尽管所有关注的示例代码都是推导出的大小,因此匿名参数避免了有关未使用参数的警告.