Uwaga Mozza 314
Oto symulacja efektów std::algorithm
wywołania ogólnego std::swap
i sytuacji, w której użytkownik udostępnia swap w przestrzeni nazw std. Ponieważ jest to eksperyment, w tej symulacji namespace exp
zamiast namespace std
.
// simulate <algorithm>
#include <cstdio>
namespace exp
{
template <class T>
void
swap(T& x, T& y)
{
printf("generic exp::swap\n");
T tmp = x;
x = y;
y = tmp;
}
template <class T>
void algorithm(T* begin, T* end)
{
if (end-begin >= 2)
exp::swap(begin[0], begin[1]);
}
}
// simulate user code which includes <algorithm>
struct A
{
};
namespace exp
{
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
// exercise simulation
int main()
{
A a[2];
exp::algorithm(a, a+2);
}
Dla mnie to drukuje:
generic exp::swap
Jeśli Twój kompilator drukuje coś innego, oznacza to, że nie implementuje poprawnie „wyszukiwania dwufazowego” dla szablonów.
Jeśli twój kompilator jest zgodny (z którymkolwiek z C ++ 98/03/11), to da to samo wyjście, które pokazuję. I w takim przypadku wydarzy się dokładnie to, czego się obawiasz. Umieszczenie twojego swap
w przestrzeni nazw std
( exp
) nie powstrzymało tego.
Dave i ja jesteśmy członkami komitetu i zajmujemy się tym obszarem normy od dziesięciu lat (i nie zawsze w porozumieniu). Ale ta kwestia została rozstrzygnięta od dawna i oboje zgadzamy się, jak została rozwiązana. Zignoruj opinię / odpowiedź Dave'a w tej dziedzinie na własne ryzyko.
Ten problem wyszedł na jaw po opublikowaniu C ++ 98. Od około 2001 roku Dave i ja zaczęliśmy pracować w tej dziedzinie . A to jest nowoczesne rozwiązanie:
// simulate <algorithm>
#include <cstdio>
namespace exp
{
template <class T>
void
swap(T& x, T& y)
{
printf("generic exp::swap\n");
T tmp = x;
x = y;
y = tmp;
}
template <class T>
void algorithm(T* begin, T* end)
{
if (end-begin >= 2)
swap(begin[0], begin[1]);
}
}
// simulate user code which includes <algorithm>
struct A
{
};
void swap(A&, A&)
{
printf("swap(A, A)\n");
}
// exercise simulation
int main()
{
A a[2];
exp::algorithm(a, a+2);
}
Wynik to:
swap(A, A)
Aktualizacja
Stwierdzono, że:
namespace exp
{
template <>
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
Pracuje! Dlaczego więc tego nie użyć?
Rozważ przypadek, że Twój A
jest szablonem klasy:
// simulate user code which includes <algorithm>
template <class T>
struct A
{
};
namespace exp
{
template <class T>
void swap(A<T>&, A<T>&)
{
printf("exp::swap(A, A)\n");
}
}
// exercise simulation
int main()
{
A<int> a[2];
exp::algorithm(a, a+2);
}
Teraz to już nie działa. :-(
Więc możesz wstawić swap
std przestrzeni nazw i sprawić, by działało. Ale trzeba pamiętać, aby umieścić swap
w A
„s nazw dla przypadku, gdy masz szablon: A<T>
. A ponieważ w obu przypadkach będzie działać, jeśli umieścić swap
w A
„s nazw, to jest po prostu łatwiejsze do zapamiętania (a uczyć innych) po prostu zrób to, że jeden sposób.