std::find терпит неудачу на std::vector‹std::reference_wrapper‹T›› с несоответствием для ошибки «operator==», когда T находится в пространстве имен

В настоящее время я работаю над большим проектом кода и хотел бы воспользоваться возможностью, чтобы узнать и использовать пространства имен. Все классы, которые я определил, находятся в одном пространстве имен Test.

Один из моих классов, называемый здесь Thing, имеет уникальный идентификатор. Мне нужно иметь возможность хранить std::vector ссылок на некоторые вещи, поэтому я использую std::reference_wrappers. В некоторых точках программы мне нужно удалить определенные std::reference_wrappers из вектора, поэтому я использую std::find:

#include <algorithm>
#include <functional>
#include <vector>

namespace Test {

class Thing {
private:
    const int id;

public:
    Thing(int id);
    const int ID() const;
};

}

Test::Thing::Thing(int id) : id(id) { }

const int Test::Thing::ID() const {
    return id;
}

inline bool operator==(const Test::Thing& lhs, const Test::Thing& rhs) {
    return lhs.ID() == rhs.ID();
}
inline bool operator!=(const Test::Thing& lhs, const Test::Thing& rhs) {
    return !(lhs == rhs);
}

int main() {
    Test::Thing t1(5);
    Test::Thing t2(7);

    auto ref1 = std::ref(t1);
    auto ref2 = std::ref(t2);

    std::vector<std::reference_wrapper<Test::Thing>> v;
    v.push_back(ref1);
    v.push_back(ref2);

    auto pos = std::find(v.begin(), v.end(), ref2);
}

Когда я пытаюсь скомпилировать это, я получаю сообщение об ошибке:

error: no match for ‘operator==’ (operand types are ‘std::reference_wrapper<Test::Thing>’ and ‘const std::reference_wrapper<Test::Thing>’)

Однако, если я удалю пространство имен, код скомпилируется правильно:

#include <functional>
#include <vector>
#include <algorithm>

class Thing {
private:
    const int id;

public:
    Thing(int id);
    const int ID() const;
};

Thing::Thing(int id) : id(id) { }

const int Thing::ID() const {
    return id;
}

inline bool operator==(const Thing& lhs, const Thing& rhs) {
    return lhs.ID() == rhs.ID();
}
inline bool operator!=(const Thing& lhs, const Thing& rhs) {
    return !(lhs == rhs);
}

int main() {
    Thing t1(5);
    Thing t2(7);

    auto ref1 = std::ref(t1);
    auto ref2 = std::ref(t2);

    std::vector<std::reference_wrapper<Thing>> v;
    v.push_back(ref1);
    v.push_back(ref2);

    auto pos = std::find(v.begin(), v.end(), ref2);
}

person Daniel G.    schedule 01.10.2019    source источник


Ответы (1)


Правильное решение — переместить операторы в пространство имен, где Поиск в зависимости от аргумента (ADL) их можно найти:

namespace Test {

class Thing {
private:
    const int id;

public:
    Thing(int id);
    const int ID() const;
};


inline bool operator==(const Thing& lhs, const Thing& rhs) {
    return lhs.ID() == rhs.ID();
}
inline bool operator!=(const Thing& lhs, const Thing& rhs) {
    return !(lhs == rhs);
}

}

Test::Thing::Thing(int id) : id(id) { }

const int Test::Thing::ID() const {
    return id;
}

[Текущий пример]

То же самое уже сделано стандартной библиотекой с такими операторами, как << для вставки потока.

person Angew is no longer proud of SO    schedule 01.10.2019