Стандарты программирования на С++. 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 class Widget { /* ... */ };

>}

то специализация >std::swap попросту невозможна, так как частичной специализации шаблона функции не существует. Лучшее, что вы можете сделать, — это добавить перегрузку функции

>namespace ??? {

> template void swap(Widget&, Widget&);

>}

Это проблематичное решение, поскольку если вы помещаете эту функцию в пространство имен, в котором находится >Widget, то многие реализации просто не в состоянии найти ее, но при этом стандарт запрещает располагать данную функцию в пространстве имен >std. Эта проблема никогда бы не возникла, если бы стандарт либо указывал, что перегрузки надо искать и в пространстве имен типа шаблона, либо позволял помещать перегружаемые функции в пространство имен >std, или (возвращаясь к основному вопросу данной рекомендации) прямо указывал, что >swap должна реализовываться с использованием шаблона класса, который может быть частично специализирован.

Ссылки

[Austern99] §A.1.4 • [Sutter04] §7 • [Vandevoorde03] §12

67. Пишите максимально обобщенный код

Резюме

Используйте для реализации функциональности наиболее обобщенные и абстрактные средства.

Обсуждение

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