|
Программирование >> Инициализация объектов класса, структура
каким доен быть тип возвращаемого значения: T U template <class T, class U> любом порядке. Как это сделать? Какой тип возвращаемого значения следует задать? ??? sum( T, U ); В нашем случае нельзя использовать ни тот, ни другой параметрический тип, иначе мы char ch; unsigned int ui; ни T, ни U нельзя использовать в качестве типа возвращаемого значения sum( ch, ui ); правильно: U sum( T, U ); неизбежно допустим ошибку: sum( ui, ch ); правильно: T sum( T, U ); Решение заключается в том, чтобы ввести в шаблон третий параметр для обозначения T1 не появляется в списке параметров шаблона функции template <class T1, class T2, class T3> типа возвращаемого значения: T1 sum( T2, T3 ); Поскольку тип возвращаемого значения может отличаться от типов аргументов функции, T1 не упоминается в списке формальных параметров. Это потенциальная проблема, так как тип T1 не может быть выведен из фактических аргументов функции. Однако, если В этом случае список аргументов шаблона <unsigned int> явно задает их типы. Поскольку аргумент шаблона теперь известен, вызов функции больше не приводит к ошибке. Обратите внимание, что при вызове функции miin5() второй аргумент равен 1024, т.е. имеет тип int. Так как тип второго формального параметра функции при явном задании аргумента шаблона установлен в unsigned int, то второй фактический параметр функции приводится к типу unsigned int с помощью стандартного преобразования целых типов. В предыдущем разделе мы говорили, что в процессе вывода аргументов шаблона к фактическим аргументам функции разрешается применять только ограниченное множество преобразований типов. Трансформация int в unsigned int в это множество не входит. Но если аргументы шаблона задаются явно, выполнять вывод типов не нужно, поскольку они уже зафиксированы. Следовательно, при явном задании аргументов шаблона для приведения типов фактических аргументов функции к типам формальных параметров можно применять любые стандартные преобразования. Помимо разрешения любых преобразований фактических аргументов функции, явное задание аргументов шаблона помогает избежать и других проблем, встающих перед программистом. Рассмотрим следующую задачу. Мы хотим определить шаблон функции с именем sum() так, чтобы его конкретизация возвращала значения типа, достаточно большого для представления суммы двух значений любых двух типов, переданных в typedef unsigned int ui type; ui type calc( char ch, ui type ui ) { ... ошибка: невозможно вывести T1 ui type loc1 = sum( ch, ui ); правильно: аргументы шаблона задан1 явно T1 и T3 - это unsigned int, T2 - это char ui type loc2 = sum< ui type, ui type >( ch, ui ); компилятора о невозможности вывести T1. Например: Не хватает возможности явно задать T1, но не T2 и T3, поскольку их можно вывести из аргументов функции при вызове. При явном задании аргументов шаблона необходимо перечислять только те, которые не могут быть выведены автоматически. Но, как и в случае аргументов функции со правильно: T3 - это unsigned int T3 выведен из типа ui ui type loc3 = sum< ui type, char >( ch, ui ); правильно: T2 - это char, T3 - unsigned int T2 и T3 выведены из типа pf ui type (*pf)( char, ui type ) = &sum< ui type >; ошибка: опускать можно только хвостовые аргументы значениями по умолчанию, опускать можно исключительно хвостовые : ui type loc4 = sum< ui type, , ui type >( ch, ui ); Встречаются ситуации, когда невозможно вывести аргументы шаблона в контексте, где конкретизируется шаблон функции; следовательно, необходимо их явно задать. Именно выявление таких ситуаций и необходимость решить проблему послужила причиной поддержки явного задания аргументов шаблона в стандартном C++. В следующем примере берется адрес конкретизированной функции sum() и передается в качестве аргумента перегруженной функции manipulate() . Как мы показали в разделе 10.2, невозможно понять, как именно нужно конкретизировать sum() , если есть только списки параметров функций manipulate() . Имеется две разных функции sum() , и обе удовлетворяют условиям вызова. Следовательно, вызов mianipulate() неоднозначен. Одним из способов разрешения такой неоднозначности является явное приведение типов. Однако лучше использовать явное задание аргументов шаблона: оно позволяет указать, как именно конкретизировать sum() , и, следовательно, выбрать нужный вариант перегруженной функции manipulate() . Например: при конкретизации sum() мы зададим аргументы шаблона явно, то избегнем сообщения template <class T1, class T2, class T3> T1 sum( T2 op1, T3 op2 ) { /* ... */ } void manipulate( int (*pf)( int,char ) ); void manipulate( double (*pf)( float,float ) ); int main() { ошибка: какой из возможн1х экземпляров sum: int sum( int,char ) или double sum( float, manipulate int sum( int,char ) или double sum( float, float )? ipulate( &sum ); берется адрес конкретизированного экземпляра double sum( float, float ) вызывается: void manipulate( double (*pf)( float, float ) ); manipulate( &sum< double, float, float > ); Отметим, что явное задание аргументов шаблона следует использовать только тогда, когда это абсолютно необходимо для разрешения неоднозначности или для конкретизации шаблона функции в контексте, где вывести аргументы невозможно. Во-первых, определение типов и значений аргументов шаблона проще оставить компилятору. А во-вторых, если м1 модифицируем объявления в программе, так что типы аргументов функции при вызове конкретизированного шаблона изменятся, то компилятор автоматически скорректирует вызов без нашего вмешательства. С другой стороны, если аргументы шаблона заданы явно, необходимо проверить, что они по-прежнему отвечают новым типам аргументов функции. Поэтому мы рекомендуем избегать явного задания аргументов шаблона. Упражнение 10.6 Назовите две ситуации, когда использование явного задания аргументов шаблона необходимо. Упражнение 10.7 template <class T1, class T2, class T3> Пусть дано следующее определение шаблона функции sum (): T1 sum( T2, T3 ); double dobj1, dobj 2; float fobj1, fobj2; char cobj1, cobj2; (a) sum( dobj1, dobj2 ); (b) sum<double,double,double>( fobj1, fobj2 ); (c) sum<int>( cobj1, cobj2 ); Какие из приведенных ниже вызовов ошибочны? Почему? (d) sum<double, ,double>( fobj2, dobj2 );
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |