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


person template boy    schedule 24.01.2015    source источник
comment
stackoverflow.com/q/4782692/19093   -  person Jiří Pospíšil    schedule 25.01.2015
comment
Отвечает ли это на ваш вопрос? что делает `using std: : swap` внутри тела реализации метода класса означает?   -  person M.J. Rayburn    schedule 27.06.2021


Ответы (2)


Комментарий «включить ADL» применяется к преобразованию

std::swap(first.mSize, second.mSize);
std::swap(first.mArray, second.mArray);

to

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 не входит в область действия.

person Community    schedule 24.01.2015
comment
Вы имеете в виду, что using std::swap - это запасной вариант для типов, для которых нет связанных пространств имен или классов? - person template boy; 25.01.2015
comment
@templateboy Да, а также типы, для которых есть связанные пространства имен, но для которых не предусмотрена пользовательская функция swap. Наиболее распространенные типы, для которых это необходимо, - это встроенные типы. - person ; 25.01.2015

Просто хотел добавить, почему эта идиома вообще используется, что похоже на дух исходного вопроса.

Эта идиома используется во многих классах библиотеки std, где реализована подкачка. Из http://www.cplusplus.com/reference/algorithm/swap/:

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

Таким образом, цель использования неквалифицированного «свопа» для замены переменных-членов в описанной вами функции состоит в том, чтобы ADL мог найти настраиваемые функции подкачки для этих классов (если они существуют где-то еще).

Поскольку эти настроенные классы не существуют в классе, на который вы ссылаетесь (mSize и mArray - это std :: size_t и int *, соответственно, в исходном примере), а std :: swap работает нормально, автор добавил комментарий, что в данном случае в этом нет необходимости, но это хорошая практика. Он получил бы те же результаты, если бы явно вызвал std :: swap, как указано в предыдущем ответе.

Почему это хорошая практика? Потому что, если у вас есть в качестве членов экземпляры классов, для которых определен настраиваемый своп, вы хотите, чтобы поведение было таким: проверьте настраиваемую функцию подкачки ... если она существует, используйте ее, если она не существует, используйте библиотеку std функции. В случаях, когда нет доступных настраиваемых функций подкачки, вы хотите, чтобы он был по умолчанию для простой реализации std :: swap, описанной в приведенной выше ссылке. Отсюда и «использование» для подкачки встроенных типов в пространство имен. Но их будут судить в последнюю очередь.

См. Также: https://stackoverflow.com/a/2684544/2012659

Если по какой-то причине вы ненавидите «использование std :: swap», я полагаю, что теоретически вы могли бы разрешить это вручную, явно вызвав std :: swap для всего, что вы хотите поменять местами, используя std :: swap и используя неквалифицированный swap для каждый известный вам настраиваемый своп определен (все еще обнаруживается с помощью ADL). Но это подвержено ошибкам ... если вы не создавали эти классы, вы можете не знать, существует ли для них настраиваемый своп. А переключение между std :: swap и swap сбивает код с толку. Лучше позволить компилятору все это обрабатывать.

person eculeus    schedule 17.04.2015