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).

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

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

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

           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)

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


Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.