在以下代码中
#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如何自动初始化为数组大小的正确值(数组是通过引用传递的)?上面的代码是如何工作的?
答案 0 :(得分: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;
}
请注意,此功能中不再有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;
}
这里也是一样的。
您的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.