Как "использование std:: swap" включает ADL?
В Что такое идиома копирования и замены Этот пример показан:
friend void swap(dumb_array& first, dumb_array& second) // nothrow
{
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.mSize, second.mSize);
swap(first.mArray, second.mArray);
}
Как именно using std::swap
включает ADL? Для ADL требуется только полное имя. Единственное преимущество, которое я вижу для using std::swap
, заключается в том, что поскольку std::swap
является шаблоном функции, вы можете использовать список аргументов шаблона в вызове (swap<int, int>(..)
).
Если это не так, то для чего же тогда using std::swap
?
2 ответа:
Комментарий "enable ADL" применяется к преобразованию
std::swap(first.mSize, second.mSize); std::swap(first.mArray, second.mArray);
К
using std::swap; swap(first.mSize, second.mSize); swap(first.mArray, second.mArray);
Вы правы, ADL требует только безусловное имя, но именно так код переделывается, чтобы использовать безусловное имя.
Просто
swap(first.mSize, second.mSize); swap(first.mArray, second.mArray);
Не будет работать, потому что для многих типов ADL не найдет
std::swap
, и никакая другая полезная реализацияswap
не находится в области видимости.
Просто хотел добавить, почему эта идиома вообще используется, что казалось духом первоначального вопроса.
Этот фразеологизм употребляется в течение многих СТД библиотеку классов, где реализуется своп. От http://www.cplusplus.com/reference/algorithm/swap/:
Многие компоненты стандартной библиотеки (в рамках std) вызывают swap в неквалифицированный образом, чтобы позволить пользовательским перегрузок для некурящих основных видах вызываться вместо этой универсальной версии: пользовательские перегрузки менять объявляется в том же пространстве имен, что и тип, для которого они предоставляются получить выбранный через зависимый от аргумента поиск по этому универсальному версия.
Таким образом, цель использования безусловного "swap" для замены переменных-членов в функции, которую вы описали, состоит в том, чтобы ADL мог найти настроенные функции swap для этих классов (если они существуют в другом месте).
Поскольку эти настраиваемые классы не существуют в классе, на который вы ссылаетесь (mSize и mArray-это std:: size_t и int*, соответственно, в исходном примере), а std::swap работает просто отлично, автор добавил комментарий, что это не было необходимо в данном случае, но хорошая практика. Он получил бы те же результаты, если бы он явно вызвал std::swap, как указано в предыдущем ответе.
Почему это хорошая практика? Потому что если у вас есть в качестве членов экземпляры классов, для которых определен пользовательский своп, вы хотите, чтобы поведение было следующим: проверьте наличие настраиваемой функции свопа...если она существует, используйте его, если он не существует, используйте функции библиотеки std. В тех случаях, когда нет настраиваемых функций подкачки, вы хотите, чтобы он был по умолчанию к простой реализации std::swap, описанной в ссылке выше. Отсюда и "использование", чтобы внести подкачку для встроенных типов в пространство имен. Но их будут судить в последнюю очередь.
См. также: https://stackoverflow.com/a/2684544/2012659
Если по какой-то причине вы ненавидите "using std:: swap", я полагаю, вы могли бы в теория решает эту проблему вручную, явно вызывая std:: swap для всего, что вы хотите поменять, используя std:: swap и используя безусловный своп для каждого пользовательского свопа, который, как вы знаете, определен (все еще найден с помощью ADL). Но это подвержено ошибкам ... если вы не были автором этих классов, вы можете не знать, существует ли для него настроенный своп. А переключение между std:: swap и swap приводит к путанице кода. Лучше позволить компилятору справиться со всем этим.