在以下代码中
#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);
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,两个阵列的大小都被打印出来.但是N如何自动初始化为数组大小的正确值(数组是通过引用传递的)?上面的代码是如何工作的?
AnT*_*AnT 32
N没有"初始化"任何东西.它不是变量.它不是一个对象.N是一个编译时常量.N仅在编译期间存在.值和N实际T值由称为模板参数推导的过程确定.双方T并N从实际类型传递到模板函数的参数推导.
在第一次调用时,参数类型是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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,此功能中没有T也没有N.在编译时,两者都被它们的实际推导值所取代.
在第一次调用中,参数类型是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;
}
Run Code Online (Sandbox Code Playgroud)
这里也是一样的.
你main基本上翻译成
int main()
{
int a[]={1,2,3,4,5,6};
int b[]={1};
cal_size_int_6(a);
cal_size_int_1(b);
}
Run Code Online (Sandbox Code Playgroud)
换句话说,你的cal_size模板生下了两个不同的功能(所谓特化的原始模板),每一个都具有不同的值N(和T硬编码到体).这就是模板在C++中的工作方式.
它的作用是因为类型a是"长度为6的数组int",类型b是"长度为1的数组int".编译器知道这一点,因此它可以调用正确的函数.特别是,第一个调用调用模板实例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"
Run Code Online (Sandbox Code Playgroud)