2015-01-24 16 views
7

W What is the copy-and-swap idiom tym przykładzie pokazano:W jaki sposób "przy użyciu std :: swap" włączyć 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); 
} 

Jak dokładnie using std::swap umożliwić ADL? ADL wymaga tylko niewykwalifikowanej nazwy. Jedyną korzyścią dla using std::swap jest to, że ponieważ std::swap jest szablonem funkcji, możesz użyć listy argumentów szablonu w wywołaniu (swap<int, int>(..)).

Jeśli tak nie jest, to jaka jest using std::swap dla?

+0

http://stackoverflow.com/q/4782692/19093 –

Odpowiedz

9

"Włącz ADL" uwaga odnosi się do przekształcenia

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

do

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

Masz rację, ADL wymaga tylko nazwy bez zastrzeżeń, ale to, w jaki sposób kod jest re -pracował, aby użyć niekwalifikowanej nazwy.

Po prostu

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

nie będzie działać, ponieważ dla wielu typów, ADL nie znajdzie std::swap, a nie inny użyteczny swap realizacja jest w zasięgu.

+0

Masz na myśli "używanie std :: swap" jest awarią dla typów, dla których nie ma powiązanych przestrzeni nazw lub klas? –

+0

@templateboy Tak, a także typy, dla których istnieją powiązane przestrzenie nazw, ale dla których nie podano niestandardowej funkcji 'swap'. Najbardziej powszechnymi typami, które są niezbędne, są wszystkie typy wbudowane. – hvd

5

Chciałem tylko dodać, dlaczego ten idiom jest w ogóle używany, co wyglądało jak duch pierwotnego pytania.

Ten idiom jest używany w wielu klasach bibliotek STD, w których zaimplementowano zamianę. Od http://www.cplusplus.com/reference/algorithm/swap/:

Wiele komponentów biblioteki standardowej (w std) wezwanie zamiany w niewykwalifikowanego sposób, aby umożliwić niestandardowe przeciążeń dla nie-podstawowych typów nazywać zamiast typowego wersji: przeciążeń zwyczaj zamiany zadeklarowane w tym samym obszarze nazw co typ, dla którego są one dostarczane są wybierane za pomocą wyszukiwania zależnego od argumentów w tej ogólnej wersji .

Zatem celem stosowania bez zastrzeżeń „swap”, aby zamienić zmienne w funkcji, którą opisana jest tak, że ADL może znaleźć niestandardowych funkcji swapowych dla tych klas (jeśli istnieją gdzie indziej).

Ponieważ te niestandardowe klasy nie istnieją w klasie, do której się odwołujesz (mSize i mArray to odpowiednio std :: size_t i int *, w oryginalnym przykładzie), a std :: swap działa po prostu W porządku, autor dodał komentarz, że nie było to konieczne w tym przypadku, ale dobre praktyki. Miałby te same wyniki, gdyby wyraźnie nazwał to std :: swap, co podkreślono w poprzedniej odpowiedzi.

Dlaczego to dobra praktyka? Ponieważ jeśli masz jako członków instancje klas, dla których zdefiniowano niestandardową zamianę, chcesz, aby zachowanie było takie: sprawdź niestandardową funkcję wymiany ... jeśli istnieje, użyj jej, jeśli nie istnieje, użyj biblioteki standardowej Funkcje. W przypadkach, w których nie ma dostępnych niestandardowych funkcji zamiany, użytkownik chce uzyskać domyślną domyślną dla prostej implementacji std :: swap opisanej w powyższym łączu. Stąd "używanie", aby wprowadzić zamianę wbudowanych typów w przestrzeń nazw. Ale te będą wypróbowane na końcu.

Zobacz także: https://stackoverflow.com/a/2684544/2012659

Jeśli z jakiegoś powodu nienawidzisz „za pomocą std :: swap”, przypuszczam, że można teoretycznie rozwiązać ten ręcznie przez jawne wywołanie std :: swap dla wszystko, czego chcesz swap przy użyciu std :: swap i użycie nieuwarunkowanej wymiany dla każdej niestandardowej wymiany, którą znasz jest zdefiniowana (nadal można znaleźć przy użyciu ADL). Ale jest to podatne na błędy ... jeśli nie stworzyłeś tych klas, możesz nie wiedzieć, czy istnieje dla nich niestandardowa wymiana. A przełączanie pomiędzy std :: swap i swap powoduje, że kod jest mylący. Lepiej pozwolić, aby kompilator sobie z tym poradził.