Бьерн Страуструп - Язык программирования С++. Главы 5-8
Страница 83. Разрешение перегрузки для шаблонной функции



8.5 Разрешение перегрузки для шаблонной функции

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

            template<class T> T sqrt(t);

            void f(int i, double d, complex z)
            {
              complex z1 = sqrt(i);  // sqrt(int)
              complex z2 = sqrt(d);  // sqrt(double)
              complex z3 = sqrt(z);  // sqrt(complex)
              // ...
            }

 Здесь для всех трех типов параметров будет создаваться по шаблону
 своя функция sqrt. Если пользователь захочет чего-нибудь иного,
 например вызвать sqrt(double), задавая параметр int, нужно
 использовать явное преобразование типа:

           template<class T> T sqrt(T);

           void f(int i, double d, complex z)
           {
             complex z1 = sqrt(double(i));  // sqrt(double)
             complex z2 = sqrt(d);  // sqrt(double)
             complex z3 = sqrt(z);  // sqrt(complex)
             // ...
           }

 В этом примере по шаблону будут создаваться определения только для
 sqrt(double) и sqrt(complex).
     Шаблонная функция может перегружаться как простой, так и шаблонной
 функцией того же имени. Разрешение перегрузки как шаблонных, так и
 обычных функций с одинаковыми именами происходит за три шагаЬ:

 Ь Эти правила слишком строгие, и, по всей видимости будут ослаблены,
 чтобы разрешить преобразования ссылок и указателей, а, возможно,
 и другие стандартные преобразования. Как обычно, при таких
 преобразованиях будет действовать контроль однозначности.

      [1] Найти функцию с точным сопоставлением параметров ($$R.13.2);
          если такая есть, вызвать ее.
      [2] Найти шаблон типа, по которому можно создать вызываемую
          функцию с точным сопоставлением параметров; если такая есть,
          вызвать ее.
      [3] Попробовать правила разрешения для обычных функций ($$r13.2);
          если функция найдена по этим правилам, вызвать ее, иначе
          вызов является ошибкой.
 В любом случае, если на первом шаге найдено более одной функции,
 вызов считается неоднозначным и является ошибкой. Например:

          template<class T>
            T max(T a, T b) { return a>b?a:b; };

          void f(int a, int b, char c, char d)
          {
            int m1 = max(a,b);  // max(int,int)
            char m2 = max(c,d); // max(char,char)
            int m3 = max(a,c);  // ошибка: невозможно
                                // создать max(int,char)
          }

 Поскольку до генерации функции по шаблону не применяется никаких
 преобразований типа (правило [2]), последний вызов в этом
 примере нельзя разрешить как max(a,int(c)). Это может сделать сам
 пользователь, явно описав функцию max(int,int). Тогда вступает
 в силу правило [3]:

          template<class T>
             T max(T a, T b) { return a>b?a:b; }

          int max(int,int);

          void f(int a, int b, char c, char d)
          {
            int m1 = max(a,b);     // max(int,int)
            char m2 = max(c,d);    // max(char,char)
            int m3 = max(a,c);     // max(int,int)
          }

 Программисту не нужно давать определение функции max(int,int),
 оно по умолчанию будет создано по шаблону.
      Можно определить шаблон max так, чтобы сработал первоначальный
 вариант нашего примера:

          template<class T1, class T2>
             T1 max(T1 a, T2 b) { return a>b?a:b; };

          void f(int a, int b, char c, char d)
          {
            int m1 = max(a,b);    // int max(int,int)
            char m2 = max(c,d);   // char max(char,char)
            int m3 = max(a,c);    // max(int,char)
          }

 Однако, в С и С++ правила для встроенных типов и операций над ними
 таковы, что использовать подобный шаблон с двумя параметрами
 может быть совсем непросто. Так, может оказаться неверно задавать
 тип результата функции как первый параметр (T1), или, по крайней
 мере, это может привести к неожиданному результату, например для
 вызова

          max(c,i);  // char max(char,int)

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

 
« Предыдущая статья   Следующая статья »