为什么找不到用命名空间中定义的类型实例化的 std::weak_ptr 的重载运算符==?

Why overloaded operator== for std::weak_ptr instantiated with type defined in namespace can't be found?

我正在使用 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;
}

Error C2678 binary '==': no operator found which takes a left-hand operand of type 'const std::weak_ptr' (or there is no acceptable conversion) test_cppunit_interpreter_base_multi_output c:\program files (x86)\microsoft visual studio 14.0\vc\include\utility 216

Bar 位于命名空间时,似乎无法找到比较器...

我是不是做错了什么?或者这可能是编译器错误?

您应该将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 也适用于全局命名空间。对于第一种情况,Baroperator== 都在同一个命名空间(即全局命名空间)中定义。

为什么第二种情况不行?

首先注意std::find定义在命名空间std中,其中定义了很多operator==(参数类型不同)。然后根据 unqualified name lookup 的规则,当在命名空间 std 处找到 operator== 时,名称查找停止。这意味着如果没有 ADL 的帮助,全局命名空间中定义的 operator== 将根本找不到。