函数模板中的魔法参数
在下面的代码中
#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
由称为模板参数推导的过程确定。 T
和N
都是从你传递给模板函数的参数的实际types中推导出来的。
在第一个调用中,参数types是int[6]
,所以编译器推导出T == int
和N == 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 == int
和N == 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的值。