Выбор кандидатов при вызове функций

230
06 января 2018, 03:19

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

https://ideone.com/JGcZDR

#include <algorithm>
using namespace std;
struct smth
{
  int x;
  void swap(smth &s)
  {
    ////// error: no matching function for call to ‘smth::swap(int&, int&)’
    ////// note: candidate: void smth::swap(smth&)
    ////// note:   candidate expects 1 argument, 2 provided
    ////swap(x, s.x);
    std::swap(x, s.x);
  }
};
int main()
{
  return 0;
}
Answer 1

Поиск неквалифицированных имен (unqualified name lookup) при вызове функции состоит из двух частей: обычного поиска и ADL-поиска.

  • Обычный поиск выполняется "изнутри наружу": из внутренней области видимости во все более и более охватывающие области видимости, пока хотя бы одно имя не найдено. Когда хотя бы одно имя найдено, обычный поиск немедленно прекращается.

    Какие области видимости просматриваются зависит от контекста. В вашем случае - это поим имени swap, использованного в определении функции-члена класса. Для такого контекста поиск выполняется в следующих областях видимости: локальная, класс smth, пространство имен ::. В процессе просмотра имя swap найдется в классе smth - это имя вашей же функции. Т.е. до поиска в глобальном пространстве имен дело не доходит вообще.

  • ADL-поиск выполняется в пространствах имен, ассоциированных с типами аргументов вызываемой функции. Но в случае фундаментального типа int ADL не выполняется - у типа int нет ассоциированных пространств имен.

Более интересным был бы пример с

struct smth
{
  std::string x;
  void swap(smth &s)
  {
    swap(x, s.x);
  }
};

В такой ситуации у типа std::string есть ассоциированное с ним пространство имен std. И ADL-поиск мог бы выполнить поиск в пространстве имен std (даже ваш using namespace std; не нужен) и найти там правильный std::swap. Однако особое правило unqualified name lookup говорит, что если обычный поиск нашел именно функцию-член класса, то ADL не выполняется вообще. Поэтому и здесь будет та же самая ошибка.

Answer 2

Можете добавить using в swap:

void swap(smth &s)
{
  using std::swap;
  swap(x, s.x);//ok
}
READ ALSO
Рефакторинг кода в Qt (C++)

Рефакторинг кода в Qt (C++)

Здравствуйте, задался довольно-таки очень простым вопросом

553
Приведение типов умных указателей C++

Приведение типов умных указателей C++

А можно ли привести тип умного указателя родительского класса к дочернему? К примеру есть есть базовый класс Models и от него наследуется класс...

297
Связные списки в с++

Связные списки в с++

Очень сложно разобраться со связными списками( Помогите разобраться в этой части кода,пожалуйста:

350
Содержимое указателя

Содержимое указателя

Немного запутался:

235