函数模板中的魔法参数

在下面的代码中

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

N没有被“初始化”到任何东西。 这不是一个variables。 这不是一个对象。 N是编译时常量。 N只在编译期间存在。 N的值以及实际的T由称为模板参数推导的过程确定。 TN都是从你传递给模板函数的参数的实际types中推导出来的。

在第一个调用中,参数types是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; } 

请注意,此函数中不再有T ,也没有N 在编译时两者都被它们的实际推导值取代。

在第一个调用中,参数types是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 ++中的工作原理。

这是因为a的types是“ int的长度为6的数组”,而b的types是“ 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" 

当你声明int a [] = {1,2,3}时,它与(或将被重写为)int a [3] = {1,2,3}相同,因为模板函数以T a [N],则N将具有3的值。