Как "использование 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 10

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 приводит к путанице кода. Лучше позволить компилятору справиться со всем этим.