Оператор сравнения для std::vector<T> не может найти оператор сравнения для T

Следующий очень простой код не скомпилируется

#include <vector>
#include <string>


namespace Foobar {
    struct Test {
        std::string f;
        std::uint16_t uuid;
    };
}

bool operator==(const Foobar::Test& lhs, const Foobar::Test& rhs){
    return lhs.f == rhs.f && lhs.uuid == rhs.uuid;
}


int main(){

    std::vector<Foobar::Test> a;
    std::vector<Foobar::Test> b;

    if(a==b){

    }

    return 0;
}

https://godbolt.org/g/zn6UgJ

Не будет компилироваться ни в один из моих компиляторов.

Хотя следующее

#include <vector>
#include <string>


namespace Foobar {
    struct Test {
        std::string f;
        std::uint16_t uuid;
    };

    bool operator==(const Foobar::Test& lhs, const Foobar::Test& rhs){
        return lhs.f == rhs.f && lhs.uuid == rhs.uuid;
    }
}



int main(){

    std::vector<Foobar::Test> a;
    std::vector<Foobar::Test> b;

    if(a==b){

    }

    return 0;
}

https://godbolt.org/g/o4pc1b

Компилирует просто отлично, что заставляет меня думать std::vector<T> Оператор сравнения выглядит в пространстве имен Tпочему он не учитывает глобальное пространство имен?

1 ответ

Решение

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

Здесь контекст поиска std::operator==(vector, vector)поэтому он начинает искать в пространстве имен std, Есть много перегрузок operator== в пространстве имен stdтаким образом, обычный поиск останавливается там и никогда не достигает глобального пространства имен.

Во втором примере перегрузка обнаруживается в зависимости от аргумента. Этот поиск выполняется специально для имен функций в вызовах функций, в дополнение к неквалифицированному поиску, и ищет имена в областях, связанных с типами аргументов вызова. В примере пространство имен Foobar связан с Foobar::Testи так, зависящий от аргумента поиск ищет это пространство имен и находит Foobar::operator==,

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

Другие вопросы по тегам