Почему ADL имеет приоритет над функцией в «пространстве имен std», но равен функции в пользовательском пространстве имен?

У меня есть два фрагмента для 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 страница …

Спасибо за все хорошие отзывы, теперь все ясно.

6

Решение

Ваш тест не проверяет, имеет ли ADL приоритет или нет перед обычным поиском, а скорее показывает, как разрешение перегрузки определяет наилучшее соответствие. Причина того, что второй контрольный пример работает, заключается в том, что std::swap является шаблоном, и при выполнении разрешения перегрузки для идеального соответствия (найденного ADL) и шаблона, функция без шаблонов имеет преимущество.

9

Другие решения

Вызов функции происходит в несколько этапов:

  1. поиск имени -> помещает функции-кандидаты в так называемые комплект перегрузки
    • это та часть, где происходит ADL, если у вас есть поиск по неквалифицированному имени
  2. вывод аргумента шаблона -> для каждого шаблона в наборе перегрузки
  3. разрешение перегрузки -> выбрать лучшее соответствие

Вы путаете часть 1 с частью 3. Поиск имени фактически поместит оба swap функции в наборе перегрузки ({N::swap, std::swap}), но часть 3 решит, какой из них позвонить в конце.

Теперь, так как std::swap является шаблоном, и стандарт говорит, что не шаблонные функции более специализированный чем шаблонные функции при выполнении разрешения перегрузки, ваш <2> звонки N::swap:

§13.3.3 [over.match.best] p1

Учитывая эти определения, жизнеспособная функция F1 определяется как лучшая функция, чем другая жизнеспособная функция F2 если […]

  • F1 это не шаблонная функция и F2 является специализацией шаблона функции […]

† Я рекомендую первые три видео эта отличная серия на предмет.

11

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector