Почему не удается найти перегруженный оператор == для std::weak_ptr, созданный с типом, определенным в пространстве имен?

Я использую Visual Studio 2015.

Любая идея, почему этот код компилируется:

#include <memory>

class Foo;
class Bar;
typedef std::pair<Foo*,std::weak_ptr<Bar>> Object;
typedef std::vector<Object> ObjectVect;

bool operator==( std::weak_ptr<Bar> left,
                 std::weak_ptr<Bar> right )
{
    return left.lock() == right.lock();
}

int main( int argc, char* argv[] )
{
    ObjectVect vect;
    Object obj;
    auto foundIter = std::find( vect.begin(), vect.end(), obj );
    return 0;
}

в то время как это дает мне ошибку:

#include <memory>

class Foo;
namespace MyNamespace
{
    class Bar;
}
typedef std::pair<Foo*,std::weak_ptr<MyNamespace::Bar>> Object;
typedef std::vector<Object> ObjectVect;

bool operator==( std::weak_ptr<MyNamespace::Bar> left,
                 std::weak_ptr<MyNamespace::Bar> right )
{
    return left.lock() == right.lock();
}

int main( int argc, char* argv[] )
{
    ObjectVect vect;
    Object obj;
    auto foundIter = std::find( vect.begin(), vect.end(), obj );
    return 0;
}

Двоичный код ошибки C2678 '==': не найден оператор, который принимает левый операнд типа 'const std::weak_ptr' (или нет приемлемого преобразования) test_cppunit_interpreter_base_multi_output c:\program files (x86)\microsoft visual studio 14.0\ vc\include\утилита 216

Похоже, ему не удается найти компаратор, когда Bar находится в пространстве имен...

Я делаю что-то неправильно? Или это может быть ошибка компилятора?


person jpo38    schedule 04.07.2017    source источник
comment
Это может помочь: stackoverflow.com/a/3623643/2550156 Вы должны поместить перегрузку оператора в то же пространство имен как ваш класс.   -  person pergy    schedule 04.07.2017
comment
Пространства имен, которые содержат тип, должны также включать свободные функции этого типа. Итак, чтобы ответить Я делаю что-то не так?, я бы сказал, что вы неправильно используете пространства имен.   -  person StoryTeller - Unslander Monica    schedule 04.07.2017
comment
@StoryTeller Бесплатная функция работает с std::weak_ptr<Bar>, который не относится к типу, содержащемуся в namespace MyNamespace.   -  person Walter    schedule 04.07.2017
comment
@Walter - он содержится там, во втором образце.   -  person StoryTeller - Unslander Monica    schedule 04.07.2017
comment
@StoryTeller НЕТ, это не так, только Bar есть.   -  person Walter    schedule 04.07.2017
comment
@Walter - это это Бар.   -  person StoryTeller - Unslander Monica    schedule 04.07.2017
comment
@Walter - И, честно говоря, я понятия не имею, о чем вы спорите. Первый пример — правильное использование пространства имен (по упущению и тип, и функция free находятся в глобальном пространстве имен). И второе — это неправильное использование пространств имен.   -  person StoryTeller - Unslander Monica    schedule 04.07.2017


Ответы (1)


Вы должны переместить operator== в пространство имен, чтобы ADL вступило в силу; ADL также проверит типы, используемые в качестве аргументов шаблона (например, MyNamespace::Bar), и добавит связанные пространства имен (например, MyNamespace) в набор поиска имен. то есть

namespace MyNamespace
{
    class Bar;
    bool operator==( std::weak_ptr<Bar> left,
                     std::weak_ptr<Bar> right )
    {
        return left.lock() == right.lock();
    }

}

Почему первый случай работает нормально?

Потому что ADL работает и для глобального пространства имен. В первом случае и Bar, и operator== определены в одном и том же пространстве имен (т. е. глобальном пространстве имен).

Почему второй случай не работает?

Во-первых, обратите внимание, что std::find определено в пространстве имен std, и в нем определено много operator== (с разными типами параметров). Затем в соответствии с правилом поиска неполного имени, когда operator== находится на пространство имен std, поиск имени останавливается. Это означает, что без помощи ADL operator==, определенный в глобальном пространстве имен, вообще не будет найден.

person songyuanyao    schedule 04.07.2017
comment
В этом случае нет необходимости ставить префикс Bar с MyNamespace::. - person user7860670; 04.07.2017
comment
Возможно, вы осмелились бы объяснить, почему нельзя использовать operator==, объявленный вне namespace, т.е. почему здесь требуется ADL. Кроме того, почему здесь работает ADL, поскольку, возможно, std::weak_ptr<> находится в std, а не MyNamespace. - person Walter; 04.07.2017
comment
По крайней мере, мне помогает работа функции find. Но я не уверен, почему нельзя объявлять оператор вне пространства имен... - person jpo38; 04.07.2017
comment
@ jpo38 - это не недопустимо, просто не ожидайте, что неквалифицированный поиск сработает. - person StoryTeller - Unslander Monica; 04.07.2017
comment
ИМХО, полный ответ должен объяснить, почему неполный поиск имени здесь не работает. - person Walter; 04.07.2017
comment
@Walter Я попытался добавить необходимые пояснения, скажите, если что-то все еще неясно. (Мне требуется некоторое время, чтобы понять, почему это не работает без ADL. И спасибо StoryTeller за подсказку поиска неквалифицированного имени!) - person songyuanyao; 04.07.2017
comment
Да, это здорово +1! - person Walter; 04.07.2017
comment
Это должно упомянуть двухэтапный поиск. - person T.C.; 04.07.2017