[Function] Comparing function objects with std::find

Hi, I'm storing function objects in a std::vector, but to remove one again, I need to find an iterator to the one I want to remove. I do this in an "unregister" function taking a single boost::function<void ()> as parameter. Inside the function I would like to use the std::find algorithm to get an iterator to that function in the vector. I'm getting compile errors, though; see the example below. How do I fix these? I'm using MSVC++ 8 (SP1), and Boost 1.33.1 (can not upgrade). Example, where in my "unregister" function I use find as in the last part of this example (i.e. I have a Listener and not a plain function pointer). This does not compile: #include <algorithm> #include <vector> #include <boost/function.hpp> using namespace std; using namespace boost; void listenerA() {} void listenerB() {} int main() { typedef function<void ()> Listener; typedef vector<Listener> ListenerVector; ListenerVector listeners; listeners.push_back(&listenerA); listeners.push_back(&listenerB); ListenerVector::iterator iter; // This compiles and works iter = find( listeners.begin(), listeners.end(), &listenerB); assert(iter != listeners.end()); // This gives: // error C2666: 'boost::operator ==' : 4 overloads have // similar conversions iter = find( listeners.begin(), listeners.end(), Listener(&listenerB)); assert(iter != listeners.end()); return 0; } Compiler errors: c:\program files (x86)\microsoft visual studio 8\vc\include\algorithm(40) : error C2666: 'boost::operator ==' : 4 overloads have similar conversions d:\development\boost_1_33_1\boost\function\function_template.hpp(583): could be 'void boost::operator ==<R,Allocator>(const boost::function0<R,Allocator> &,const boost::function0<R,Allocator> &)' [found using argument-dependent lookup] with [ R=void, Allocator=std::allocator<void> ] d:\development\boost_1_33_1\boost\function\function_base.hpp(609): or 'bool boost::operator ==<boost::function<Signature>>(Functor,const boost::function_base &)' [found using argument-dependent lookup] with [ Signature=void (void), Functor=boost::function<void (void)> ] d:\development\boost_1_33_1\boost\function\function_base.hpp(600): or 'bool boost::operator ==<_Ty>(const boost::function_base &,Functor)' [found using argument-dependent lookup] with [ _Ty=boost::function<void (void)>, Functor=boost::function<void (void)> ] or 'built-in C++ operator==(void (__thiscall boost::function0<R,Allocator>::dummy::* )(void), void (__thiscall boost::function0<R,Allocator>::dummy::* )(void))' with [ R=void, Allocator=std::allocator<void> ] while trying to match the argument list '(boost::function<Signature>, const boost::function<Signature>)' with [ Signature=void (void) ] c:\program files (x86)\microsoft visual studio 8\vc\include\algorithm(74) : see reference to function template instantiation '_InIt std::_Find<std::_Vector_iterator<_Ty,_Alloc>,_Ty>(_InIt,_InIt,const _Ty &)' being compiled with [ _InIt=std::_Vector_iterator<Listener,std::allocator<Listener>>, _Ty=Listener, _Alloc=std::allocator<Listener> ] d:\development\misc\functionvector\functionvector.cpp(35) : see reference to function template instantiation '_InIt std::find<std::_Vector_iterator<_Ty,_Alloc>,boost::function<Signature>>(_InIt,_InIt,const _Ty &)' being compiled with [ _InIt=std::_Vector_iterator<Listener,std::allocator<Listener>>, _Ty=Listener, _Alloc=std::allocator<Listener>, Signature=void (void) ] Best regards, Christian

Hah, what a coincidence. I see that Hajo Kirchhoff has just asked basically the same question two hours before me. See "[Boost-users] [function] function_equal or function::operator== ambiguous overload?" Is this something which has changed in 1.36.0? Will go check with an older version... Best regards, Christian Christian Larsen skrev:
Hi,
I'm storing function objects in a std::vector, but to remove one again, I need to find an iterator to the one I want to remove. I do this in an "unregister" function taking a single boost::function<void ()> as parameter. Inside the function I would like to use the std::find algorithm to get an iterator to that function in the vector. I'm getting compile errors, though; see the example below. How do I fix these?
I'm using MSVC++ 8 (SP1), and Boost 1.33.1 (can not upgrade).
Example, where in my "unregister" function I use find as in the last part of this example (i.e. I have a Listener and not a plain function pointer). This does not compile:
#include <algorithm> #include <vector> #include <boost/function.hpp>
using namespace std; using namespace boost;
void listenerA() {} void listenerB() {}
int main() { typedef function<void ()> Listener; typedef vector<Listener> ListenerVector;
ListenerVector listeners;
listeners.push_back(&listenerA); listeners.push_back(&listenerB);
ListenerVector::iterator iter;
// This compiles and works iter = find( listeners.begin(), listeners.end(), &listenerB);
assert(iter != listeners.end());
// This gives: // error C2666: 'boost::operator ==' : 4 overloads have // similar conversions iter = find( listeners.begin(), listeners.end(), Listener(&listenerB));
assert(iter != listeners.end());
return 0; } [SNIP]

Christian Larsen skrev:
Hah, what a coincidence. I see that Hajo Kirchhoff has just asked basically the same question two hours before me.
Hm, found an answer in a previous thread: http://lists.boost.org/boost-users/2005/05/11987.php But then what about using contains? This doesn't compile either: #include <boost/function.hpp> using namespace boost; void listenerA() {} void listenerB() {} int main() { typedef function<void ()> Listener; Listener a = listenerA; Listener b = listenerB; bool equal; // None of these compile: equal = (a == b); equal = function_equal(a, b); equal = a.contains(b); equal = a.contains(a); return 0; } What to do, revert to raw function pointers? --Christian

Christian Larsen:
int main() { typedef function<void ()> Listener;
Listener a = listenerA; Listener b = listenerB;
bool equal;
// None of these compile: equal = (a == b); equal = function_equal(a, b); equal = a.contains(b); equal = a.contains(a);
return 0; }
As you've seen, 'a' contains listenerA. It's not possible to compare two boost::function objects for equality. Boost.Signals solves the 'remove' problem by returning a dedicated token from 'add' (boost::connection in its case) which you can then pass to 'remove'.

Peter Dimov skrev: [SNIP]
As you've seen, 'a' contains listenerA. It's not possible to compare two boost::function objects for equality. Boost.Signals solves the 'remove' problem by returning a dedicated token from 'add' (boost::connection in its case) which you can then pass to 'remove'.
Aha! That is the elegant solution I was looking for. Thanks a lot. --Christian

Christian Larsen skrev:
I'm storing function objects in a std::vector, but to remove one again, I need to find an iterator to the one I want to remove. I do this in an "unregister" function taking a single boost::function<void ()> as parameter. Inside the function I would like to use the std::find algorithm to get an iterator to that function in the vector. I'm getting compile errors, though; see the example below. How do I fix these?
Sorry for spamming the list. I think I found a solution to my original problem. But still I'm not completely satisfied, because it seems there is no way I can store the function objects and use those for both adding and later removing. If I try to store them using boost::function I get the same error as before when calling either Source::add or Source::remove, obviously because std::find tries to compare two boost::function's internally. This example does what I expect, but would it somehow be possible to store the bind(&listenerA, 42) for later use in the remove call? (Having to write the same in both places is error prone.) #include <algorithm> #include <iostream> #include <vector> #include <boost/function.hpp> #include <boost/bind.hpp> using namespace std; using namespace boost; typedef function<void ()> Listener; typedef vector<Listener> ListenerVector; struct Source { ListenerVector listeners; template <typename F> void add(F f) { ListenerVector::iterator iter = find( listeners.begin(), listeners.end(), f); assert(iter == listeners.end() && "already added"); listeners.push_back(f); } template <typename F> void remove(F f) { ListenerVector::iterator iter = find( listeners.begin(), listeners.end(), f); assert(iter != listeners.end() && "not added"); listeners.erase(iter); } void signal() { for (ListenerVector::iterator iter = listeners.begin(); iter != listeners.end(); ++iter) { (*iter)(); } } }; void listenerA(int) { cout << "Hello, "; } void listenerB(float) { cout << "World!\n"; } int main() { Source s; s.add(bind(&listenerA, 42)); s.add(bind(&listenerB, 3.14f)); s.signal(); // "Hello, World!" s.remove(bind(&listenerA, 42)); s.signal(); // "World!" s.remove(bind(&listenerB, 3.14f)); s.signal(); // <nothing> return 0; } Best regards, Christian
participants (2)
-
Christian Larsen
-
Peter Dimov