Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm using Visual Studio 2015.

Any idea why this code compiles:

#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;
}

while this one gives me error:

#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

Looks like it failes to find the comparator when Bar is located in a namespace...

Am I doing something wrong? Or could this be a compiler bug?

like image 325
jpo38 Avatar asked Jul 04 '17 10:07

jpo38


1 Answers

You should move operator== into the namespace to make ADL take effect; ADL will also examine the types used as the template arguments (i.e. MyNamespace::Bar) and add the associated namespaces (i.e MyNamespace) to the set of name lookup. i.e.

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

}

Why the 1st case works fine?

Because ADL works for global namespace too. For the 1st case both Bar and operator== is defined in the same namespace (i.e. the global namespace).

Why the 2nd case doesn't work?

Firstly note that std::find is defined in the namespace std, and there're many operator==s defined in it (with different parameter types). Then according to the rule of unqualified name lookup, when operator== is found at the namespace std, the name lookup stops. That means without the help of ADL, the operator== defined in the global namespace won't be found at all.

like image 149
songyuanyao Avatar answered Oct 06 '22 01:10

songyuanyao