В следующем коде
#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
ничем не "инициализируется". Это не переменная. Это не объект. 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
порождает две разные функции (так называемые специализации исходного шаблона), каждое из которых имеет разные значения 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"
когда вы объявляете int a[] = {1,2,3}, это то же самое, что (или будет переписано как) int a[3] = {1,2,3}, поскольку шаблонизированная функция получает аргумент в виде T a[N], то N будет иметь значение 3.