6

Test.h

#ifndef TEST_H
#define TEST_H

#include <memory>

template <class Type>
bool operator==(const std::weak_ptr<Type>& wp1, const std::weak_ptr<Type>& wp2)
{
std::shared_ptr<Type> sp1;

if(!wp1.expired())
    sp1 = wp1.lock();

std::shared_ptr<Type> sp2;

if(!wp2.expired())
    sp2 = wp2.lock();

return sp1 == sp2;
}

#endif

Test.cpp

#include "Test.h"
#include <list>


int main()
{
typedef std::list< std::weak_ptr<int> > intList;

std::shared_ptr<int> sp(new int(5));
std::weak_ptr<int> wp(sp);

intList myList;
myList.push_back(wp);

myList.remove(wp); //Problem
}

The program won't compile due to myList.remove():

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\list(1194): error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::tr1::weak_ptr<_Ty>' (or there is no acceptable conversion) 1>
with 1> [ 1> _Ty=int 1> ]

But you can see the following defined in Test.h:

bool operator==(const std::weak_ptr<Type>& wp1, const std::weak_ptr<Type>& wp2)

What is the problem?

user987280
  • 1,578
  • 1
  • 14
  • 24

1 Answers1

6

The operator overload is found by argument-dependent lookup, and your function doesn't apply as it's not defined in namespace std (the namespace of the argument types, and the context of the expression inside std::list::remove).

You should use remove_if to apply a custom predicate function. In general, don't attempt to define operators for types inside libraries you cannot modify.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Great, thanks for the info. I would like to avoid this altogether but I need to remove from a list of weak_ptrs. Would it be a bad idea to define operator== inside namespace std? I have only used remove_if with a unary predicate with the element itself as an argument. I would need to compare the element with the pointer I am trying to remove. Is it possible to call the predicate with a second argument? – user987280 Apr 15 '12 at 22:47
  • 1
    You could replace your `remove` with `myList.remove_if(std::bind(std::operator==, wp, std::placeholders::_1));`, although I'd rename the comparison function from `operator==` to something like `equals`. Or you could use a lambda function in place of `std::bind`. – Fraser Apr 15 '12 at 22:50
  • [`std::list::remove_if`](http://en.cppreference.com/w/cpp/container/list/remove) only takes one argument which is the predicate, so you don't need the iterators. You're maybe thinking of the general [`std::remove_if`](http://en.cppreference.com/w/cpp/container/list/remove) defined in ``, which has slightly different behaviour to `list`'s. See the "Notes" section in the link. And yes, _1 is the placeholder for each element passed by `remove_if` into the bound function, so your `equals` function looks good as is. – Fraser Apr 15 '12 at 23:40