【问题标题】:How does this template magic determine array parameter size?这个模板魔法如何确定数组参数大小?
【发布时间】:2011-01-23 22:55:54
【问题描述】:

在下面的代码中

#include<iostream>

 template<typename T,size_t N> 
 void cal_size(T (&a)[N])
 { 
     std::cout<<"size of array is: "<<N<<std::endl;
 }

 int main()
 {
     int a[]={1,2,3,4,5,6};
     int b[]={1};

     cal_size(a);
     cal_size(b);
 }

正如预期的那样,两个数组的大小都被打印出来了。但是 N 如何自动初始化为数组大小的正确值(数组是通过引用传递的)?上面的代码是如何工作的?

【问题讨论】:

标签: c++ templates


【解决方案1】:

N 不会“初始化”任何东西。它不是一个变量。它不是一个对象。 N 是编译时常量。 N 仅在编译期间存在。 N 的值以及实际的T 由称为模板参数推导的过程确定。 TN 都是从您传递给模板函数的参数的实际类型推导出来的。

在第一次调用中,参数类型是int[6],因此编译器推断出T == intN == 6,为此生成一个单独的函数并调用它。让我们将其命名为cal_size_int_6

void cal_size_int_6(int (&a)[6]) 
{ 
  std::cout << "size of array is: " << 6 << std::endl; 
} 

请注意,此函数中不再有 TN。两者都在编译时被它们的实际推导值替换。

在第一次调用中,参数类型是int[1],因此编译器推断出T == intN == 1,并为此生成一个单独的函数并调用它。让我们将其命名为cal_size_int_1

void cal_size_int_1(int (&a)[1]) 
{ 
  std::cout << "size of array is: " << 1 << std::endl; 
} 

这里也一样。

你的main 基本上翻译成

int main() 
{ 
  int a[]={1,2,3,4,5,6}; 
  int b[]={1}; 

  cal_size_int_6(a); 
  cal_size_int_1(b); 
} 

换句话说,您的cal_size 模板产生了两个不同的函数(原始模板的所谓特化),每个函数都有不同的N 值(和T)硬编码到正文中。这就是模板在 C++ 中的工作方式。

【讨论】:

  • 事实上,comeau 接受了这一点:template&lt;unsigned char S&gt; void f(int(&amp;)[S]); int main() { int a[UCHAR_MAX+1]; f(a); }。有趣的是,我什至不确定标准对这个 sn-p 的看法(似乎说调用成功,但没有指定函数体中 S 的值)。在任何情况下,comeau 都会给 S 类型“unsigned char”,但在函数体中给它实际值(超出其范围)。
【解决方案2】:

之所以有效,是因为a 的类型是“int 的长度为 6 的数组”,b 的类型是“int 的长度为 1 的数组”。编译器知道这一点,因此它可以调用正确的函数。特别是,第一次调用调用模板实例cal_size&lt;6&gt;(),第二次调用调用cal_size&lt;1&gt;(),因为它们是唯一匹配其各自参数的模板实例。

如果您尝试调用显式模板实例,则只有在您获得正确大小的情况下才会起作用,否则参数将不匹配。考虑以下几点:

cal_size(a);    // ok, compiler figures out implicitly that N=6
cal_size<int, 6>(a); // also ok, same result as above
cal_size<int, 5>(a); // ERROR: a is not of type "array of length 5 of int"

【讨论】:

    【解决方案3】:

    当您声明 int a[] = {1,2,3} 时,它与(或将被重写为) int a[3] = {1,2,3} 相同,因为模板化函数正在接收参数以 T a[N] 的形式,则 N 的值为 3。

    【讨论】:

      猜你喜欢
      • 2011-09-16
      • 2011-03-23
      • 1970-01-01
      • 2011-06-27
      • 2018-01-24
      • 1970-01-01
      • 2014-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多