Дополнительно
Как перегрузить std::swap()
std::swap()
используется многими контейнерами std (такими как std::list
и std::vector
) во время сортировки и даже присвоения.
Но std-реализация swap()
очень обобщена и довольно неэффективна для пользовательских типов.
Таким образом, эффективность может быть достигнута путем перегрузки std::swap()
с реализацией, специфичной для пользовательских типов. Но как реализовать ее так, чтобы она использовалась контейнерами std?
112
4
Правильный способ перегрузить swap - записать его в том же пространстве имен, что и то, что вы меняете, чтобы его можно было найти через argument-dependent lookup (ADL). Особенно легко это сделать следующим образом:
Внимание Mozza314
Вот моделирование эффектов универсального
std :: algorithm
, вызывающегоstd :: swap
, и когда пользователь предоставляет свой своп в пространстве имен std. Поскольку это эксперимент, это моделирование используетnamespace exp
вместоnamespace std
.Для меня это распечатывается:
Если ваш компилятор печатает что-то другое, то он неправильно реализует «двухфазный поиск» для шаблонов.
Если ваш компилятор соответствует (любому из C ++ 98/03/11), то он даст тот же вывод, который я показываю. И в этом случае именно то, чего вы боитесь, произойдет. И помещение вашего
swap
в пространство именstd
(exp
) не помешало этому случиться.Дейв и я оба являемся членами комитета и работаем в этой области стандарта в течение десятилетия (и не всегда согласны друг с другом). Но этот вопрос был решен в течение длительного времени, и мы оба согласны с тем, как он был решен. Не обращайте внимания на экспертное мнение / ответ Дейва в этой области на свой страх и риск.
Этот выпуск стал известен после публикации C ++ 98. Начиная примерно с 2001 года мы с Дейвом начали работать в этой области. И это современное решение
Выход это:
Обновить
Было сделано наблюдение, что:
работает! Так почему бы не использовать это?
Рассмотрим тот случай, когда ваш
A
является шаблоном класса:Теперь это не работает снова. :-(
Таким образом, вы можете поместить
swap
в пространство имен std и заставить его работать. Но вам нужно помнить, чтобы поместитьswap
в пространство именA
для случая, когда у вас есть шаблон:A < T >
. И поскольку оба случая будут работать, если вы поместите «swap» в пространство имен «A», просто легче запомнить (и научить других) просто сделать это одним способом.Вам не разрешается (по стандарту C++) перегружать std::swap, однако вам разрешено добавлять специализации шаблонов для ваших собственных типов в пространство имен std. Например.
тогда использование в контейнерах std (и в любом другом месте) будет использовать вашу специализацию вместо общей.
Также обратите внимание, что реализация swap в базовом классе недостаточно хороша для ваших производных типов. Например, если у вас есть
это будет работать для базовых классов, но если вы попытаетесь поменять местами два производных объекта, то будет использована общая версия из std, потому что шаблонизированный swap является точным совпадением (и это позволяет избежать проблемы замены только 'базовых' частей ваших производных объектов).
ПРИМЕЧАНИЕ: Я'обновил это, чтобы удалить неправильные биты из моего последнего ответа. D'oh! (спасибо puetzk и j_random_hacker за то, что указали на это).
Хотя правильно, что обычно не следует добавлять что-либо в пространство имен std::, добавление специализаций шаблонов для определяемых пользователем типов разрешено. Перегрузка функций - нет. Это тонкая разница :-)
Специализация std::swap будет выглядеть следующим образом:
Без бита template это была бы перегрузка, которая не определена, а не специализация, которая разрешена. Предлагаемый @Wilka' подход изменения пространства имен по умолчанию может сработать в пользовательском коде (из-за того, что Koenig lookup предпочтет версию без пространства имен), но это' не гарантировано, и на самом деле не должно (реализация STL должна использовать полностью квалифицированное std::swap).
Существует тема на comp.lang.c++.moderated с длинным обсуждением этой темы. Большая часть из них посвящена частичной специализации, хотя (в настоящее время нет хорошего способа сделать это).