Шаблоны функций (окончание)

   
На этом шаге мы закончим рассматривать шаблоны функций.

   
Перечислим основные свойства параметров шаблона.

  • Имена параметров шаблона должны быть уникальными во всем определении шаблона.
  • Список параметров шаблона функций не может быть пустым, так как при этом теряется возможность параметризации и
    шаблон функций становится обычным определением конкретной функции.
  • В списке параметров шаблона функций может быть несколько параметров. Каждый из них должен начинаться со
    служебного слова class. Например, допустим такой заголовок шаблона:

                 template <class type1, class type2>
    

       
    Соответственно, неверен заголовок:

                 template <class type1, type2, type3>
    
  • Недопустимо использовать в заголовке шаблона параметры с одинаковыми именами, т.е. ошибочен
    такой заголовок:

                template <class t, class t, class t>
    
  • Имя параметра шаблона (в наших примерах type1, type2 и т.д.) имеет в определяемой шаблоном функции все права имени типа,
    т.е. с его помощью могут специализироваться формальные параметры, определяться тип возвращаемого функцией значения и типы любых объектов,
    локализованных в теле функции. Имя параметра шаблона видно во всем определении и скрывает другие использования того же идентификатора в области,
    глобальной по отношению к данному шаблону функций. Если внутри тела определяемой функции необходим доступ к внешним объектам с тем же именем,
    нужно применять операцию изменения области видимости. Следующая программа иллюстрирует указанную особенность имени параметра шаблона функций:
  • //OOР36_1.СРР - параметр шаблона и внешняя переменная с
    //	тем же именем.
    #include <iostream.h>
    int N;   // Инициализирована по умолчанию нулевым значением.
    // Функция определяет максимальное из двух значений параметров.
    template <class N>
    N max(N x, N y)
    {  N a = x;
       cout << "\nСчетчик обращений N = " << ++::N;
       if (a < y) a = y;
       return a;
    }
    void main()
    {
       int a = 12, b = 42;
       max(a,b);
       float z = 66.3, f = 222.4;
       max(z,f);
    }
    

    Текст этой программы можно взять здесь.

       
    Результат выполнения программы:

            Счетчик обращений N = 1 
            Счетчик обращений N = 2
    

       
    Итак, одно имя нельзя использовать для обозначения нескольких параметров одного шаблона, но в разных шаблонах функций
    могут быть одинаковые имена у параметров шаблонов. Ситуация здесь такая же, как и у формальных параметров при определении обычных функций,
    и на ней можно не останавливаться подробнее. Действительно, раз действие параметра шаблона заканчивается в конце определения шаблона,
    то соответствующий идентификатор свободен для последующего использования, в том числе и в качестве имени параметра другого шаблона.

       
    Все параметры шаблона функций должны быть обязательно использованы в спецификациях параметров определения функции.
    Таким образом, будет ошибочным такой шаблон:

           template <class A, class В, class C> 
           В func(A n, С m) {В valu; ... }
    

       
    В данном неверном примере остался неиспользованным параметр шаблона с именем B. Его применений в качестве типа возвращаемого функцией
    значения и для определения объекта valu в теле функции недостаточно.

       
    Определяемая с помощью шаблона функция может иметь любое количество непараметризованных формальных параметров. Может быть не
    параметризовано и возвращаемое функцией значение. Например, в следующей программе шаблон определяет семейство функций, каждая из которых
    подсчитывает количество нулевых элементов одномерного массива параметризованного типа:

    //OOР36_2.СРР  - прототип шаблона для семейства функций.
    #include <iostream.h>
    template <class D>
    long count0(int,   D   *);   // Прототип шаблона.
    void main ()
    { 
      int A[] = {1, 0, 6, 0, 4, 10};
      int n = sizeof (A) /sizeof A[0] ;
      cout << "\ncount0(n,A)  =  " <<  count0(n,A);
      float X[] = {10.0, 0.0, 3.3, 0.0, 2.1};
      n = sizeof(X)/sizeof X[0];
      cout << "\ncount0(n,X)  = " << count0(n,X);
    }
    // Шаблон функций для подсчета количества нулевых элементов
    // в массиве.
    template <class  T>
    long count0(int size, T* array)
    { 
      long k  =  0;
      for (int i = 0; i < size; i++) 
           if (int(array[i]) == 0) k++;
      return k;
    }
    

    Текст этой программы можно взять здесь.

       
    Результат выполнения программы:

          count0(n,A) = 2
          count0(n,X) = 2
    

       
    В шаблоне функций count0() параметр T используется только в спецификации одного формального
    параметра array. Параметр size и возвращаемое функцией значение имеют явно заданные непараметризованные типы.

       
    Как и при работе с обычными функциями, для шаблонов функций существуют определения и описания. В качестве описания шаблона
    функций используется прототип шаблона:

            template <список_параметров_шаблона>
    

       
    В списке параметров прототипа шаблона имена параметров не обязаны совпадать с именами тех же параметров в определении шаблона. Это
    и продемонстрировано в программе.

       
    При конкретизации шаблонного определения функции необходимо, чтобы при вызове функции типы фактических параметров, соответствующие одинаково
    параметризованным формальным параметрам, были одинаковыми. Для определенного выше шаблона функций с прототипом

       template <class  E> void swap(E,E); 
    

    недопустимо использовать такое обращение к функции:

       int  n  =  4;   double d =  4.3;
       swap(n,d); // Ошибка в типах параметров.
    

       
    Для правильного обращения к такой функции требуется явное приведение типа одного из параметров. Например, вызов:

       swap(double(n),d); // Правильные типы параметров.
    

    приведет к конкретизации шаблонного определения функций с параметром типа double.

       
    При использовании шаблонов функций возможна перегрузка как шаблонов, так и функций. Могут быть шаблоны с одинаковыми именами,
    но разными параметрами. Или с помощью шаблона может создаваться функция с таким же именем, что и явно определенная функция. В обоих
    случаях "распознавание" конкретного вызова выполняется по сигнатуре, т.е. по типам, порядку и количеству фактических параметров.

       
    На следующем шаге мы рассмотрим шаблоны классов.



    Вы можете оставить комментарий, или Трекбэк с вашего сайта.

    Оставить комментарий