Анимация
JavaScript
|
Главная Библионтека ментов функций наиболее эффективен? В общем случае сложные типы эффективнее всего передавать по ссылке, а скалярные - по значению. (К скалярным типам относятся арифметические типы, описанные ранее, например enum, указатели и указатели на члены класса.) Для сложных типов это позволяет избежать ненужных затрат времени на вызовы конструкторов и деструкторов, а для скалярных типов - избыточных способов доступа к переменным, предоставляемых ссылками. Не забудьте, что в языке С++ указатели на ссылки не допускаются. Таким образом, если объект класса Т уже является ссылкой, то новую ссылку на нее создавать не следует. Несложный анализ оптимальных типов параметров функции приводит к следующему алгоритму. Рассмотрим тип параметра с именем ParameterType. Если класс Т - это ссылка на некоторый тип, классы ParameterType и т совпадают (ссылки на ссылки не допускаются). В противном случае, если класс Т - это скалярный тип (int, float и т.п.), то класс ParameterType - это класс Т (основные типы лучще всего передавать по значению), иначе класс ParameterType является типом const Т& (неэлементарные типы лучще передавать по ссылке). Одно из достоинств этого алгоритма состоит в том, что он позволяет избежать ошибки, связанной с использованием ссылки на ссылку, которая может возникнуть при совместном использовании функций bind2nd и mem fun из стандартной библиотеки. Класс TypeTraits легко реализовать с помощью приема, который мы уже применяли, и определенных выше характеристик ReferencedType и isPrimitive. template <typename т> class TypeTraits { ... как и раньше ... public: typedef Select<isStdArith isPointer isMemberPointer, T, ReferencedType&>::Result ParameterType; К сожалению, эта схема не позволяет передавать по значению параметры перечислимых типов, поскольку невозможно определить, является заданный тип перечислимым или нет. Класс TypeTraits:: ParameterType используется в шаблонном классе Functor, определенном в главе 5. 2.10.4. Удаление квалификаторов Имея тип Т, можно легко получить константу, очень похожую на обычную константу const Т. Однако выполнить обратную операцию (т.е. удалить квалификатор const) намного труднее. Кроме того, иногда возникает необходимость избавиться и от квалификатора типа volatile. Рассмотрим, например, создание интеллектуального указателя SmartPtr (глава 7). Если бы мы захотели предоставить пользователю возможность создавать интеллектуальные указатели на константные объекты, например SmartPtr<const widget>, пришлось бы модифицировать указатель на объект класса widget. В этом случае в классе SmartPtr следовало бы создавать объект класса widget на основе константного объекта. Реализовать такой "ликвидатор" достаточно просто. Для этого нужно применить частичную шаблонную специализацию. template <typename т> class TypeTraits { ... как и раньше ... private: template <class и> struct UnConst typedef и Result; [ template <class U> struct UnConst<const u> { typedef и Result; public: typedef unConst<T>Result NonConstType; 2.10.5. Применение класса TypeTraits Класс TypeTraits предоставляет много интересных возможностей. Например, с помошью описанных выше приемов можно реализовать процедуру Сору, использую-шую функцию BitBlast (проблема, упомянутая в разделе 2.10). Для этого можно применить класс TraitsType, позволяюший получить информацию о двух итераторах, и шаблонный класс int2Type, осушествляюший диспетчеризацию вызова либо функции BitBlast, либо классической процедуры копирования. enum CopyAlgoSelector { Conservative, Fast }; классическая процедура применяется ко всем типам template <typename init, typename OutIt> Outit Copylmpl(init first, init last, Outit result, int2Type<Conservative> for (; first != last; ++first, ++result) *result = *fi rst; return result; Быстрая процедура применяется только для указателей на простые данные template <typename init, typename Outlt> Outit Copylmpl (mm first, init last, Outit result, int2Type<Fast>) const si2e t n = last-first; BitBlast(first, result, n * sizeof(*first)); return result + n; template <typename init, typename Outlt> Outit Copydnit first, init last, Outit result) typedef TypeTraits<lnlt>::PointeeType SrcPointee; typedef TypeTraits<Outlt>::PointeeType DestPointee; enum { copyAlgo = TypeTraits<lnIt>::isPointer && TypeTraits<OutIt>::isPointer && TypeTraits<SrcPointee>::isStdFundamental && TypeTraits<DestPointee>::i sStdFundamental && sizeof(SrcPointee) == sizeof(DestPointee) ? Fast : Conservative }; return Copylmpi(first, last, result, lnt2Type<copyAlgo>); Несмотря на то что процедура Сору сама по себе не слишком сложна, в ней есть один интересный момент. Перечислимое значение сорулТдо позволяет делать выбор среди разных реализаций. Логика этого выбора такова: функция BitBlast используется, если оба итератора являются указателями, и оба типа, на которые ссьглаются указатели, являются основными и имеют одинаковый размер. Последнее условие необычно. Рассмотрим такой фрагмент кода. int* р1 = int* р2 = unsigned int* рЗ = CopyCpl, р2, рЗ); В этом варианте функция Сору вызовет функцию быстрого копирования, как и положено, хотя типы источника и адресата отличаются друг от друга. Недостаток функции Сору заключается в том, что она не ускоряет то, что можно было бы ускорить. Например, для простой структуры, характерной для языка С, содержащей лишь данные элементарных типов - так называемой структуры старых простых данных (old plain data stmcture), или POD-структуры, стандартом предусмотрено побитовое копирование. Однако функция Сору не распознает простые структуры и вызывает медленную процедуру копирования. Здесь, кроме класса TypeTraits, нужно снова применить классические характеристики. template <typename т> struct SupportBitwiseCopy { enum { result = TypeTraits<T>::isStdFundamental }; template <typename init, typename OutIt> Outit CopyClnit first, init last, Outit result, lnt2Type<true>) typedef TypeTraits<lnlt>::PointeeType SrcPointee; typedef TypeTraits<Outlt>::PointeeType DestPointee; enum { useBitBlast = typeTraits<Inlt>::isPointer && typeTraits<Outlt>::isPointer && SupportBitwiseCopy<SrcPointee>::result && SupportBitwiseCopy<DestPointee>::result && sizeof(SrcPointee) == sizeof(DestPointee) } return Copylmpi(first, last, lnt2Type<useBitBlast>); Теперь, чтобы применить функцию BitBlast для POD-типов, достаточно специализировать шаблонный класс SupportBitwiseCopy и задать в нем значение true. templateo struct SupportBitwiseCopy<MyCopy> { enum { result = true }; 2.10.6, Заключение В табл. 2.1 показано все множество характеристик, реализованных в библиотеке Loki. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [ 17 ] 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |