2011-11-01 112 views
22

下面的代码返回一个堆栈分配数组的大小:这个C++代码是什么意思?

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

,但我不能换我的头周围的语法。 特别是T (&) [size]部分...

+1

[为什么要在C++中以这种令人困惑的方式定义的“引用数组”)(http://stackoverflow.com/questions/6456253/why-is-reference-to-array-defined-in-这样易混淆的方式) – sharptooth

+7

不完全重复 –

+0

您可能想要使用别名模板并编写可能更易于阅读的别名“”。 –

回答

24

但我无法用头来包装语法。特别是T (&) [size]部分...

该部分是对数组的引用。破译任何C和C++ 声明有"right-left rule"

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

函数不能通过值接受数组类型,而只能通过指针或引用接受数组类型。参考用于避免其第一元件(也称为阵列衰减)的阵列的指针的隐式转换:

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 
} 

在它上面声明具有相同的附图对一个阵列参数的函数模板,但随着char(&)[size]返回值的类型(这是这里的“右 - 左规则”可以理解的) 。请注意,函数调用不会在运行时发生,这就是函数模板siz的定义不必要的原因。 sizeof siz(x)基本上是说“如果siz(x)被称为”“,返回值的大小是多少。

得到一个数组的元素计数作为一个编译时间常数的旧C/C++的方法是:

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

是什么和必要的parens? –

+0

@JasonS - 为了避免看起来像引用'T' – Flexo

+0

啊,好吧...和'(T&)[size]''也不起作用? (对不起,没有C编译器启动并运行) –

4

It's成为类型名的函数(模板可以具有不同typenames使用)和外部的大小。然后它返回这个大小。

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

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); 
} 

这项计划失败,编译:

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。在这个例子中,虽然你所关心的所有示例代码都是推导的大小,因此匿名参数可以避免关于未使用参数的警告。