У меня есть два фрагмента для ADL для демонстрационных целей. Оба фрагмента были скомпилированы VC10, gcc & компиляторы Comeau C ++, и результат одинаков для всех трех.
<1> ADL против использования директивы пользовательского пространства имен:
#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {}
}
namespace M
{
void swap(N::T,N::T) {}
}
int main()
{
using M::swap;
N::T o1,o2;
swap(o1,o2);
}
Результат компиляции:
error C2668: 'M::swap' : ambiguous call to overloaded function
could be 'void M::swap(N::T,N::T)'
or 'void N::swap(N::T,N::T)' [found using argument-dependent lookup]
Это ожидается, поскольку ADL не имеет приоритета над обычным результатом поиска, плюс ADL не является гражданином 2-го класса, результат поиска ADL объединен с обычным (не ADL) безусловным поиском. Вот почему у нас есть двусмысленность.
<2> ADL против использования директивы пространства имен std:
#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {} //point 1
}
namespace M
{
void swap(N::T,N::T) {}
}
int main()
{
using std::swap;
N::T o1,o2;
swap(o1,o2);
}
Этот компилируется нормально.
Результат компилятор выбирает результат ADL (он принимает прецедент std :: swap), что означает N::swap()
в «точке 1» будет вызван. Только когда отсутствует точка 1 (скажем, если я закомментирую эту строку), компиляция будет использовать отступление std::swap
вместо.
Обратите внимание, что этот способ использовался во многих местах как способ перезаписи std::swap
,
Но мой вопрос: почему ADL имеет приоритет над «пространством имен std» (case2), но считается равным определенной пользователем функции пространства имен (case1)?
Есть ли абзац в стандарте C ++, который так говорит?
================================================== ===============================
Редактировать после прочтения полезных ответов, может быть полезно для других.
Итак, я настроил мой фрагмент 1 & теперь двусмысленность исчезла, и компиляция явно предпочитает функцию Nontemplate при выполнении разрешения перегрузки!
#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {}
}
namespace M
{
template<class T>
void swap(N::T,N::T) {}
}
int main()
{
using M::swap;
N::T o1,o2;
swap(o1,o2); //here compiler choose N::swap()
}
Я также настроил свой фрагмент 2. Просто, чтобы двусмысленность выглядела просто для удовольствия!
#include <algorithm>
namespace N
{
struct T {};
template<class _Ty> inline
void swap(_Ty& _Left, _Ty& _Right)
{
_Ty _Tmp = _Move(_Left);
_Left = _Move(_Right);
_Right = _Move(_Tmp);
}
}
namespace M
{
void swap(N::T,N::T) {}
}
int main()
{
using std::swap;
N::T o1,o2;
swap(o1,o2);
}
gcc и comeau оба говорят о двусмысленности, как и ожидалось:
"std::swap" matches the argument list, the choices that match are:
function template "void N::swap(_Ty &, _Ty &)"function template "void std::swap(_Tp &, _Tp &)"
Кстати, VC10 глупо, как обычно, пусть это пройдет нормально, если я не уберу ‘использование std :: swap’.
Еще немного, что можно написать: перегрузка C ++ может быть сложной (30+ страниц в стандарте C ++), но в приложении B есть очень читаемая 10 страница …
Спасибо за все хорошие отзывы, теперь все ясно.
Ваш тест не проверяет, имеет ли ADL приоритет или нет перед обычным поиском, а скорее показывает, как разрешение перегрузки определяет наилучшее соответствие. Причина того, что второй контрольный пример работает, заключается в том, что std::swap
является шаблоном, и при выполнении разрешения перегрузки для идеального соответствия (найденного ADL) и шаблона, функция без шаблонов имеет преимущество.
Вызов функции происходит в несколько этапов†:
Вы путаете часть 1 с частью 3. Поиск имени фактически поместит оба swap
функции в наборе перегрузки ({N::swap, std::swap}
), но часть 3 решит, какой из них позвонить в конце.
Теперь, так как std::swap
является шаблоном, и стандарт говорит, что не шаблонные функции более специализированный чем шаблонные функции при выполнении разрешения перегрузки, ваш <2>
звонки N::swap
:
§13.3.3 [over.match.best] p1
Учитывая эти определения, жизнеспособная функция
F1
определяется как лучшая функция, чем другая жизнеспособная функцияF2
если […]
F1
это не шаблонная функция иF2
является специализацией шаблона функции […]
† Я рекомендую первые три видео эта отличная серия на предмет.