Attention Mozza314
Voici une simulation des effets d'un générique std::algorithm
appelant std::swap
, et ayant à l'utilisateur de fournir à leurs swap dans l'espace de noms std. Comme c'est une expérience, cette simulation utilise namespace exp
au lieu de 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);
}
Pour moi, cela m'affiche:
generic exp::swap
Si votre compilateur imprime quelque chose de différent, alors il n'est pas correctement mise en œuvre de "two-phase de recherche" pour les modèles.
Si votre compilateur est conforme (à l'un de C++98/03/11), puis il donnera le même résultat que je montre. Et dans ce cas, exactement ce dont vous avez peur qui va arriver, arrive. Et de mettre votre swap
en l'espace de noms std
(exp
) n'a pas arrêter de se produire.
Dave et moi sommes tous deux membres du comité et nous avons travaillé en cette zone de la norme pour une décennie (et pas toujours en accord les uns avec les autres). Mais ce problème est réglé depuis longtemps, et nous avons tous deux d'accord sur la façon dont il a été réglé. Le mépris de Dave avis d'expert/réponse dans ce domaine à vos risques et périls.
Ce problème est venu à la lumière après le C++98 a été publié. À partir de 2001 Dave et j'ai commencé à travailler cette zone. Et c'est la solution moderne:
// 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);
}
// Output is:
swap(A, A)
Mise à jour
Une observation a été faite que:
namespace exp
{
template <>
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
œuvres! Alors pourquoi ne pas l'utiliser?
Prenons le cas que votre A
est un modèle de classe:
// 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);
}
Maintenant, il ne fonctionne pas encore. :-(
Si vous pouviez mettre des swap
en l'espace de noms std et de le faire travailler. Mais vous aurez besoin de se rappeler de mettre swap
en A
's espace de noms pour le cas où vous avez un modèle: A<T>
. Et puisque les deux cas ne fonctionnera que si vous mettez de l' swap
en A
's espace de noms, il est simplement plus facile à retenir (et à enseigner aux autres) de le faire que d'une seule manière.