operator== and list::remove()
Asked Answered
E

1

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?

Eliott answered 15/4, 2012 at 21:34 Comment(2)
not sure, but can you try to define the bool operator== with const references?Indus
Whoops, I had it that way originally and forgot to change it back. Same problem with const references.Eliott
A
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.

Apostatize answered 15/4, 2012 at 22:17 Comment(3)
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?Eliott
You could replace your remove with myList.remove_if(std::bind(std::operator==<int>, 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.Stansbury
std::list::remove_if 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 defined in <algorithm>, 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.Stansbury

© 2022 - 2024 — McMap. All rights reserved.