Внимание Моцца314
Вот симуляция эффектов универсального std::algorithm
, вызывающего std::swap
, и позволяющего пользователю предоставить своп в пространстве имен std. Поскольку это эксперимент, в этом моделировании используется namespace exp
вместо 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);
}
Для меня это распечатывается:
generic exp::swap
Если ваш компилятор печатает что-то другое, значит, он неправильно реализует «двухфазный поиск» для шаблонов.
Если ваш компилятор соответствует (любому из C ++ 98/03/11), то он выдаст тот же вывод, который я показываю. И в этом случае произойдет именно то, чего вы боитесь. И помещение вашего swap
в пространство имен std
(exp
) не помешало этому произойти.
Дейв и я оба являемся членами комитета и работаем в этой области стандарта в течение десятилетия (и не всегда в согласии друг с другом). Но этот вопрос уже давно решен, и мы оба согласны с тем, как он решен. Не обращайте внимания на мнение / ответ Дейва в этой области на свой страх и риск.
Эта проблема появилась после публикации C ++ 98. Начиная примерно с 2001 года Дейв и я начали работать в этой области . И это современное решение:
// 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);
}
Вывод:
swap(A, A)
Обновление
Было сделано замечание, что:
namespace exp
{
template <>
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
работает! Так почему бы не использовать это?
Рассмотрим случай, когда ваш A
является шаблоном класса:
// 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);
}
Теперь это больше не работает. : - (
Чтобы вы могли поместить swap
в пространство имен std и заставить его работать. Но вам нужно помнить, чтобы поместить swap
в пространство имен A
для случая, когда у вас есть шаблон: A<T>
. И поскольку оба случая сработают, если вы поместите swap
в пространство имен A
, просто будет легче запомнить (и научить других) просто сделать это одним способом.