【问题标题】:What does this C++ code mean?这段 C++ 代码是什么意思?
【发布时间】:2011-11-01 13:13:08
【问题描述】:

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

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

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

【问题讨论】:

标签: c++ templates


【解决方案1】:

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

该部分是对数组的引用。有 "right-left rule" 用于破译任何 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
}

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

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

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

【讨论】:

  • & 周围的括号是必要的吗?
  • @JasonS - 需要括号以避免看起来像对T的引用数组
  • 啊,好吧...和(T&amp;)[size] 也不起作用? (抱歉,没有启动并运行 C 编译器)
  • @JasonS 不,这与T&amp; 相同。括号清楚地表明&amp; 不是指数组元素的类型。 (不过,C 编译器对测试它没有多大用处 - C 中没有引用!)
  • @awoodland:啊!灯终于亮了。所以引用 T 数组而不是引用数组。
【解决方案2】:

T (&amp;) [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&amp; [size] 看起来像一个引用数组,否则是非法的。

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

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多