Polymorphic functors in std::for_each
-
03-07-2019 - |
Question
I'm trying to use stl algorithm for_each without proliferating templates throughout my code. std::for_each wants to instantiate MyFunctor class by value, but it can't since its abstract. I've created a functor adapter class which passes a pointer around and then derefernces it when appropriate.
My Question:
Does the STL or Boost already have such an adapter class? I don't want to have to reinvent the wheel!
struct MyFunctor {
virtual ~MyFunctor() {}
virtual void operator()(int a) = 0;
}
namespace {
template<typename FunctorType, typename OperandType> struct
FunctorAdapter
{
FunctorAdapter(FunctorType* functor) : mFunctor(functor) {}
void operator()(OperandType& subject)
{
(*mFunctor)(subject);
}
FunctorType* mFunctor;
}; }
void applyToAll(MyFunctor &f) {
FunctorHelper<MyFunctor, int> tmp(&f);
std::for_each(myvector.begin(), myvector.end(), tmp); }
Cheers,
Dave
Solution
tr1::ref may help you here --- it's meant to be a reference wrapper so that you can pass normal objects by reference to bind or function objects (even abstract ones) by reference to standard algorithms.
// requires TR1 support from your compiler / standard library implementation
#include <functional>
void applyToAll(MyFunctor &f) {
std::for_each(
myvector.begin(),
myvector.end(),
std::tr1::ref(f)
);
}
However, NOTE that compilers without decltype support MAY reject passing a reference to an abstract type... so this code may not compile until you get C++0x support.
OTHER TIPS
You could use the function adapters (and their shims) from functional
.
#include <functional>
using namespace std;
for_each( vec.begin(), vec.end(), :mem_fun_ptr( &MyClass::f ) );
If your container contains pointers-to-objects, use mem_fun_ptr
, else use mem_fun
. Next to these, there are wrappers for member functions that take 1 argument: mem_fun1_ptr
and mem_fun1
.
@Evan: indeed, you could call the member function with the same argument for each object. The first argument of the mem_fun1
wrappers is the this
pointer, the second is the member function argument:
for_each( vec.begin(), vec.end(), bind2nd( mem_fun_ptr( &MyClass::f ), 1 ) );
With more arguments, it becomes more readable to create a loop yourself, or create a custom functor that has const member variables representing the arguments.
why not use BOOST_FOREACH?
Sounds like you could benefit from Boost::Function.
If I remember correctly it's a header only library too, so it's easy to get it going with it.
What about forgetting all the wrapping of the functor pointer, and instead use
bind(functor_pointer,mem_fun1(&MyFunctor::operator());
as the functor? that way, you don't have to worry about managing the copy in any way shape or form.
Building on @xtofl's answer, since the array contains int's and not "this" pointers, I think the correct incantation is
class MyClass
{
virtual void process(int number) = 0;
};
MyClass *instance = ...;
for_each( vec.begin(), vec.end(), binder1st(instance, mem_fun_ptr(&MyClass::process) );
The only difference versus @xtofl's code is binder1st rather than binder2nd. binder2nd allows you to pass teh same number to various "this" pointers. binder1st allows you to pass various numbers to one "this" pointer.