函数模板中的魔术参数

时间:2010-03-05 02:04:11

标签: c++ templates

在以下代码中

#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如何自动初始化为数组大小的正确值(数组是通过引用传递的)?上面的代码是如何工作的?

3 个答案:

答案 0 :(得分:32)

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模板会生成两个不同的函数(所谓的原始模板的特化),每个函数的值都不同{ {1}}(和N)硬编码到身体中。这就是模板在C ++中的工作方式。

答案 1 :(得分:8)

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

如果您尝试调用显式模板实例,则仅在您获得正确的大小时才会起作用,否则参数将不匹配。请考虑以下事项:

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"

答案 2 :(得分:1)

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