find () используя перегруженный оператор ==

Я пытаюсь найти элемент в векторе, используя перегруженный оператор == (). Однако при использовании type1 в следующем коде выходные данные равны 1 и 0 (не найдено). С помощью type2 дает 1 и 1. Среда — Xubuntu 12.04 и g ++ версии 4.6.3.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef pair<string, int> type1;
struct type2: public type1 {};
#define TYPE type1

bool operator== (const TYPE& lhs, const TYPE& rhs) {
return lhs.first == rhs.first;
}

int main()
{
vector<TYPE> vec;
TYPE v1, v2;

v1.first = "abc"; v1.second = 1; vec.push_back(v1);
v2.first = "abc"; v2.second = 2;

cout << (v1 == v2) << endl;
cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;
}

8

Решение

Ответ @AlexanderGessler неполный в нескольких деталях. Итак, давайте играть компилятором для обоих выражений и обоих типов, не так ли?

Выражение 1

cout << (v1 == v2) << endl;

Во-первых, для обоих type1 а также type2, поиск безусловного имени начинается в main() функция объема наружу, и находит свой собственный operator== функция в глобальном масштабе.

Во-вторых, поиск имени в зависимости от аргумента (ADL) находит шаблон функции operator== за std::pair от namespace std, На самом деле, ADL находит гораздо больше std::operator== шаблоны функций (те из std::vector а также std::string, так как вы включили и эти заголовки).

Заметка: ADL также находит соответствие для type2потому что его базовый класс type1 добавлю namespace std к набору связанных с ним пространств имен.


3.4.2 Поиск имени в зависимости от аргумента [basic.lookup.argdep]

— Если T является типом класса (включая объединения), его ассоциированные классы:
сам класс; класс, членом которого он является, если таковой имеется; И его
прямые и косвенные базовые классы. Его связанные пространства имен являются
пространства имен, членами которых являются связанные с ним классы.


В третьих, вычет аргумента шаблона происходит для всех найденных шаблонов функций. За type1, только шаблон функции для std::pair переживет вычет аргумента (и выводит свои аргументы шаблона, чтобы быть std::string а также intсоответственно). Однако для type2, нет набора шаблонных аргументов, которые будут соответствовать type2 это не экземпляр std::pair шаблон.

В-четвертых, разрешение перегрузки вступает в игру. За type1обе ваши собственные функции operator== и std::operator== Шаблон функции имеет одинаковый ранг (точное совпадение). Поэтому тай-брейк выберет вашу не шаблонную функцию. За type2, есть только одна жизнеспособная функция, поэтому разрешение перегрузки не вступает в игру, и ваша функция будет выбрана.

Вывод 1: type1 а также type2 даст тот же ответ (ваша версия выбрана), хотя и по разным причинам.

Выражение 2

cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;

Здесь нам нужно сначала разрешить звонок find, Из-за вашего using namespace std;Поиск безусловного имени уже найден (каламбур не предназначен) std::find, но даже без использования директивы ADL на std::vector Итератор нашел бы это. Это выведет третий аргумент шаблона для std::find либо type1 или же type2,

В std::findвызов operator== найден. Опять же, обычный поиск будет выполняться первым. Однако это происходит изнутри namespace std, Найдет несколько operator== шаблоны функций (для std::vector, std::string а также std::pair). Как только кандидаты в одной области обнаруживаются при поиске без оговорок, эта фаза поиска имен прекращается.

Однако ADL все еще выполняется. Обратите внимание, что глобальное пространство имен не является связанным пространством имен для type1 потому что это только typedef в классе в namespace std, Таким образом, для type1, ADL не находит ничего нового. По сравнению, type2 действительно имеет глобальное пространство имен в качестве связанного пространства имен, и поэтому ADL найдет ваше operator== Шаблон функции в этом случае.

За type1, шаблон-аргумент-дедукция находит std::string а также int в качестве аргументов шаблона для operator== шаблон функции для std::pair, За type2, снова нет набора шаблонных аргументов, которые будут соответствовать type2 это не экземпляр std::pair шаблон.

Это оставляет разрешение перегрузки. За type1есть только одна жизнеспособная функция (экземпляр std::operator== шаблон), а разрешение перегрузок не входит в игру. За type2есть также только одна жизнеспособная функция (жизнеспособная, потому что для нее требуется только стандартная derived-to-base преобразование). Следовательно, разрешение перегрузки также не входит в игру.

Вывод 2: за type1 (std версия) и type2 (ваша версия) вы получите разные результаты.

Резюме

Просто потому, что эти вещи могут быть очень сложными с множественными перегрузками в разных пространствах имен, вот сводная таблица со святой троицей (поиск имени, вывод аргумента и разрешение перегрузки). Для каждого этапа и для каждого типа я перечислил выживших кандидатов после этого этапа. Нижний ряд показывает вызванную функцию.

Выражение 1

+---------------------+-----------------+-----------------+
| phase               | type1           | type2           |
+---------------------+-----------------+-----------------+
| unqualified lookup  |    ::operator== |    ::operator== |
| ADL                 | std::operator== | std::operator== |
+---------------------+-----------------+-----------------+
| argument deduction  |    ::operator== |    ::operator== |
|                     | std::operator== |                 |
+---------------------+-----------------+-----------------+
| overload resolution |    ::operator== |    ::operator== |
+---------------------+-----------------+-----------------+

Выражение 2

+---------------------+-----------------+-----------------+
| phase               | type1           | type2           |
+---------------------+-----------------+-----------------+
| unqualified lookup  | std::operator== | std::operator== |
| ADL                 |                 |    ::operator== |
+---------------------+-----------------+-----------------+
| argument deduction  | std::operator== |    ::operator== |
+---------------------+-----------------+-----------------+
| overload resolution | std::operator== |    ::operator== |
+---------------------+-----------------+-----------------+

Обратите внимание, что неквалифицированный поиск находит другое имя в зависимости от области, в которой он запускается (область функции внутри глобальной области по сравнению с областью пространства имен), и что ADL аналогичным образом находит другое имя в зависимости от того, какое пространство имен считается связанным (namespace std против глобального пространства имен).

5

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

std::pair имеет значение по умолчанию operator== в пространстве имен std, который является шаблоном для произвольных пар, сравнивая оба first и second поля. Этот оператор выбирается в одном из четырех случаев, а именно find с TYPE == type1, Детали немного сложнее, хотя:

Что на самом деле происходит для TYPE == type1 есть (поправьте меня, если я ошибаюсь)

  • за v1 == v2 ADL (Аргумент зависимый поиск имени) применяется, чтобы найти operator== в stdЭто означает, что этот оператор добавляется к обычному набору перегрузки. Однако версия без шаблона в текущем модуле перевода по-прежнему предпочтительнее шаблона operator== от std,
  • std::find вызов происходит в течение stdтаким образом ищите operator== начинается прямо в std, Он находит одно совпадение (без использования ADL!) И, следовательно, не ищет вмещающую область, которая содержала бы собственный оператор OP.

И для TYPE == type2

  • v1 == v2 легко — он непосредственно находит operator== во вложенном пространстве имен.
  • std::find также экземпляры в std, но пользовательский оператор из основной области действия добавляется в набор разрешений перегрузки с использованием ADL, а затем оказывается более конкретным, чем оператор в std,
8

std::pair имеет свой operator== это имеет приоритет над вашим собственным.

1

Я думаю, что вам лучше использовать find_if вместо того, чтобы найти. Он принимает предикат, поэтому вы можете просто определить свой компаратор как обычную функцию / функтор и передать его.

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