Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphic functors in std::for_each

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

like image 736
Dave Hillier Avatar asked Jan 24 '23 01:01

Dave Hillier


2 Answers

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.

like image 189
xtofl Avatar answered Jan 26 '23 15:01

xtofl


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.

like image 27
Aaron Avatar answered Jan 26 '23 14:01

Aaron