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

1

8

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?

Swanherd answered 4/7, 2017 at 10:12 Comment(7)
This may help: https://mcmap.net/q/57817/-where-should-non-member-operator-overloads-be-placed You should put the operator overload in the same namespace as your class.Educationist
Namespaces that contain a type, should include the free functions of that type as well. So to answer "Am I doing something wrong?", I'd say you are using namespaces wrong.Fateful
@StoryTeller The free function works on std::weak_ptr<Bar>, which is not a type contained in namespace MyNamespace.Sheepish
@Sheepish - It is contained there, in the second sample.Fateful
@StoryTeller NO, it is not, only Bar is.Sheepish
@Sheepish - The it is Bar.Fateful
@Sheepish - And frankly, I have no Idea what you are arguing for. The first example is proper use of namespace (by omission, both type and free function are in the global namespace). And the second is imporper use of namespaces.Fateful
C
12

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.

Clariceclarie answered 4/7, 2017 at 10:17 Comment(8)
In this case there is no need to prefix Bar with MyNamespace::.Satiety
Perhaps you could dare to explain why the operator== declared outside of the namespace cannot be used, i.e. why ADL is required here. Also, how come ADL works here, since arguably std::weak_ptr<> is in std, not MyNamespace.Sheepish
At least it heps me having by find function work. But I'm not convinced why it be invalid to declare the operator outside the namespace...Swanherd
@Swanherd - It's not invalid, just don't expect unqualified lookup to work.Fateful
IMHO a complete answer should explain why unqualified name lookup does not work here.Sheepish
@Sheepish I tried to add the necessary explanations, tell me if something is still not clear. (It takes me some time to confirm why it doesn't work without ADL. And thanks StoryTeller about the hint of unqualified name lookup!)Clariceclarie
Yes, that's great +1!Sheepish
This should mention two-phase lookup.Oversew

© 2022 - 2024 — McMap. All rights reserved.