Стандарты программирования на С++. 101 правило и рекомендация | страница 121
Примеры
Пример. >std::swap
. Базовый шаблон >swap
обменивает два значения >а
и >b
путем создания копии >temp
значения >а
, и присваиваний >a = b
и >b = temp
. Каким образом расширить данный шаблон для ваших собственных типов? Пусть, например, у вас есть ваш собственный тип >Widget
в вашем пространстве имен >N
:
>namespace N {
> class Widget {/*...*/};
>}
Предположим, что имеется более эффективный путь обмена двух объектов >Widget
. Что вы должны сделать для того, чтобы он использовался стандартной библиотекой, — перегрузить >swap
(в том же пространстве имен, где находится >Widget
; см. рекомендацию 57) или непосредственно специализировать >std::swap
? Стандарт в данном случае невразумителен, и на практике используются разные методы (см. рекомендацию 65). Сегодня ряд реализаций корректно решают этот вопрос, предоставляя перегруженную функцию в том же пространстве имен, где находится >Widget
. Для представленного выше нешаблонного класса >Widget
это выглядит следующим образом:
>namespace N {
> void swap(Widget&, Widget&);
>}
Заметим, что если >Widget
является шаблоном
>namespace N {
> template
>}
то специализация >std::swap
попросту невозможна, так как частичной специализации шаблона функции не существует. Лучшее, что вы можете сделать, — это добавить перегрузку функции
>namespace ??? {
> template
>}
Это проблематичное решение, поскольку если вы помещаете эту функцию в пространство имен, в котором находится >Widget
, то многие реализации просто не в состоянии найти ее, но при этом стандарт запрещает располагать данную функцию в пространстве имен >std
. Эта проблема никогда бы не возникла, если бы стандарт либо указывал, что перегрузки надо искать и в пространстве имен типа шаблона, либо позволял помещать перегружаемые функции в пространство имен >std
, или (возвращаясь к основному вопросу данной рекомендации) прямо указывал, что >swap
должна реализовываться с использованием шаблона класса, который может быть частично специализирован.
[Austern99] §A.1.4 • [Sutter04] §7 • [Vandevoorde03] §12
67. Пишите максимально обобщенный код
Используйте для реализации функциональности наиболее обобщенные и абстрактные средства.
Когда вы пишете тот или иной код, используйте наиболее абстрактные средства, позволяющие решить поставленную задачу. Всегда думайте над тем, какие операции накладывают меньшее количество требований к интерфейсам, с которыми они работают. Такая привычка сделает ваш код более обобщенным, а следовательно, в большей степени повторно используемым и более приспособленным ко внесению изменений в его окружение.