Search code examples
c++templatesstlmem-fun

Using std::vector<T*>::push_back with std::mem_fun and std::bind1st


I'm trying to use std::vector<T*>::push_back with std::mem_fun and std::binder1st, but it doesnt seem to be feasible, can this be done?

I've tried to exemplify with the code below.

#include <vector>
#include <functional>
#include <iostream>

using namespace std;

struct A {
        int _Foo;
        virtual int AFoo() { return _Foo; };
};

struct B: public A {
        int BFoo(int bar) { return _Foo+bar ; };
};
struct C: public A {
        int CFoo() { return --_Foo; };
};

class MyContainer
{
        static const int MyArraySize = 100;
        A* MyArray[MyArraySize];

public:
        MyContainer() {
                int half = MyArraySize / 2;
                for( int i=0; i< half; ++i )
                        MyArray[i] = new B;
                for( int i=half; i < MyArraySize; ++i )
                        MyArray[i] = new C;
        }

        template<class T, class Fn1>
        int Execute( Fn1 func )
        {
                int count = 0;
                for( int i=0; i< MyArraySize; ++i ){
                        T* t = dynamic_cast<T*>(MyArray[i]);
                        if( t )
                        {
                                func(t);
                                ++count;
                        }
                }
                return count;
        }

        template<class T, class Res, class Arg>
        int Execute( mem_fun1_t<Res, T, Arg> func, Arg argument )
        {
                return Execute<T>( binder2nd< mem_fun1_t<Res,T,Arg> >( func, argument ) );
        }

        template<class T>
        vector<T*> GetItems()  // <-- This is the problem function
        {
                vector<T*> ret;
                Execute<T>( bind1st( mem_fun(&vector<T*>::push_back), ret ) );
                return ret;
        }
};

int main( int argc, char* argv[] )
{
        MyContainer cont;
        cont.Execute<B>( mem_fun(&B::BFoo), 10 );
        cont.Execute<C>( mem_fun(&C::CFoo) );
        vector<B*> v = cont.GetItems<A>();  // <-- the problem function is called here.
        cout << "v.size = " << v.size() << endl;
}

My goal is to have a container class to which I can tell it to execute a function receiving the selected items ('A' objects or 'A' derivate objects) as parameters. But I didn't manage to use std::vector::push_pack with it.


Solution

  • The problem is that binder1st defines operator() as:

    operator() (const typename Operation::second_argument_type& x) const
    

    and mem_fun1_t defines operator() as:

    S operator() (T* p, A x) const
    

    The problem is that push_back is defined as:

    void vector<T>::push_back(const T &x)
    

    So what we end up with is this:

    void mem_fun1_t::operator()(vector<T *> *p, const T *&x)
    

    And:

    void binder1st::operator()(const T *&&x)
    

    In other words, a reference to a reference to a pointer. A reference to a reference doesn't exist in C++. The only decent way I can think of fixing this is to use boost::bind instead:

    vector<T*> ret;
    Execute<T>( boost::bind( mem_fun(&vector<T*>::push_back), &ret,  _1) );
    return ret;
    

    Also note that you had a bug, and need to pass bind &ret instead of just ret (as mem_fun expects a pointer, mem_fun_ref would work however).