|
Программирование >> Разработка устойчивых систем
friend Box operator+<>(const Вох<Т>&, const Вох<Т>&): friend ostreamS operator <>(ostreani&. const Box<T>&): tempiate<cl ass T> Box<T> operator+Cconst Box<T>& bl. const Box<T>& b2) { return Box<T>(bl.t + b2.t): tempiate<c1ass T> ostream& operator (ostream& os. const Box<T>& b) { return OS [ b.t ]: int mainO { Box<int> bid). b2(2): cout bl + b2 endl: [3] cout bl + 2 endl: Автоматические преобразования отсутствуют! } III:- В этом примере определяются внешние операторы сложения и вывода в поток. В функции mainQ проявляется главный недостаток такого подхода: автоматические преобразования (как в выражении Ы+2) становятся невозможными, потому что они не поддерживаются шаблонами. При внутреннем ( нешаблонном ) определении программа получается короче и надежнее: : С05:Вох2.срр Определение нешаблонных операторов linclude <iostream> using namespace std: tempiate<class T> class Box { T t: public: Box(const T& theT) : t(theT) {} friend Box operator+(const Box<T>& bl. const Box<T>& b2) { return Box<T>(bl.t + b2.t): friend ostreamS operator (ostream& os. const Box<T>& b) { return OS [ b.t ]: int mainO { Box<int> bid). b2(2): cout bl + b2 endl: [3] cout bl + 2 endl: [3] } III:- Поскольку операторы являются обычными функциями (перегружаемыми для каждой специализации Box - в данном случае для int), неявные преобразования действуют нормально, и выражение bl+2 допустимо. Учтите, что один тип не может быть объявленным дружественным по отношению к Box и вообще какому-либо шаблону класса. Речь идет о типе Т, а вернее, о том типе, по которому параметризован шаблон класса. Насколько нам известно, не существует сколько-нибудь обоснованных причин для такого запрета, но пока объявление friend class Т считается недопустимым и вызывает ошибку компиляции. Идиомы программирования с применением шаблонов Язык является орудием мышления, поэтому новые языковые возможности обычно порождают новые приемы. В этом разделе мы рассмотрим ряд распространенных идиом, появившихся с момента включения шаблонов в язык С++. Характеристики Шаблоны характеристик, концепция которых была впервые предложена Натаном Майерсом (Nathan Myers), предназначаются для группировки объявлений, зависящих от типа. В сущности, характеристики позволяют смешивать некоторые типы и значения с контекстами, в которых они используются, без ущерба для удобочитаемости и простоты сопровождения программы. Простейшим примером шаблона характеристик является класс numeric limits, определяемый в файле <limits>. Определение основного щаблона выглядит так: tempiate<class Т> class numericjimits { public: static const bool is specialized - false: static T minO throwO; Вы можете точно указать, какие специализации шаблона являются друзьями класса. В примерах предыдушего раздела дружественной была только специализация шаблона функции f с тем же типом, по которому специализировался шаблон Friendly. Например, дружественной для класса Friendly<int> была только специализация f<int>(const Friendly<int>&). Поэтому параметр шаблона Friendly использовался для специализации f в объявлении friend. При желании мы могли бы сделать конкретную фиксированную специализацию f дружественной для всех экземпляров Friendly: Внутри Friendly: friend void f<>(const Friendly<doub1e>&); После замены Т на double специализация f для double получает доступ ко всем закрытым и защищенным членам любой специализации Friendly. Как и прежде, специализация f<double>() создается лишь при явном вызове. Аналогично, если объявить нешаблонную функцию без параметров, зависящих от Т, эта функция становится дружественной для всех специализаций Friendly: Внутри Friendly: friend vote g(int): g(int) является другом всех специализаций Friendly Как всегда, неуточненная функция g(int) должна определяться на уровне файла (в пространстве имен, содержащем Friendly). Также можно сделать все специализации f дружественными для всех специализаций Friendly при помощи так называемых дружественных шаблонов: tempiate<class Т> class Friendly { tempiate<class U> friend void f<>(const Friendly<U>&); Поскольку аргумент в объявлении дружественного шаблона не зависит от Т, в этих дружественных отношениях допускаются любые комбинации Т и U. Дружественные шаблоны, как и вложенные, могут использоваться внутри нешаблонных классов. static Т тахО throwO: static const int digits = 0: static const int digitslO = 0: static const bool is signed = false: static const bool isjnteger = false: static const bool is exact = false: static const int radix = 0: static T epsilonO throwO: static T round error() throwO: static const int min exponent = 0: static const int rnin exponentlO = 0: static const int max exponent = 0: static const int max exponentlO = 0: static const bool hasjnfinity = false: static const bool has quiet NaN = false: static const bool has signaling NaN = false: static const f1oat denorm style has denorm = denorm absent: static const bool has denorm loss = false: static T infinit.yO throwO: static T quiet NaN() throwO: static T signaling NaN() throwO: static T denorm min() throwO: static const bool is iec559 = false: static const bool is bounded = false: static const bool is modulo = false: static const bool traps = false: static const bool tinyness before = false: static const float round style round style = round toward zero: В заголовке <limits> определяются специализации для всех основных числовых типов (переменная is specialized равна true). Например, основание системы счисления для экспоненты в вещественном типе double может быть получено при помощи выражения numeric limits<double>::radix. Наименьшее доступное целое число определяется выражением numeric limits<int>::min(). Не все члены numeric limits относятся ко всем основным типам (например, функция epsilon() имеет смысл только для вещественных типов). Значения, которые всегда являются целыми, определяются в виде статических переменных numeric limits. Те, которые могут оказаться нецелыми (например, минимальное значение float), реализуются в виде статических подставляемых функций. Такое различие объясняется тем, что С++ позволяет инициализировать в определении класса только целочисленные статические переменные. В главе 3 было показано, как при помощи классов характеристик управлять средствами обработки символьных данных в строковых классах. Классы std::string и std::wstring являются специализациями шаблона std::basic string, который определяется следующим образом: tempiate<class charT, class traits = char traits<charT>. class allocator = allocator<charT> > class basic string: Параметр шаблона charT представляет базовый тип символов, обычно это char или wchar t. Основной шаблон char traits обычно остается пустым, а специализации для char и wchar t предоставляются стандартной библиотекой. Далее приведена спецификация специализации char traits<char> в соответствии со стандартом С++:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |