Магические аргументы в шаблонах функций

В следующем коде

#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 автоматически получает инициализацию до правильного значения размера массива (массивы передаются по ссылке)? Как работает этот код?

Ответ 1

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 и no 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 генерирует две разные функции (так называемые специализации исходного шаблона), каждая из которых имеет разные значения NT), жестко закодированные в теле. То, как работают шаблоны на С++.

Ответ 2

Это работает, потому что тип 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"

Ответ 3

когда вы объявляете int a [] = {1,2,3}, он совпадает с (или будет переписан как) int a [3] = {1,2,3}, поскольку шаблонная функция получает аргумент в форме T a [N], то N будет иметь значение 3.