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.
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).
The easiest way to call member functions on the entire set of items in your container is to use for_each
:
using namespace std;
using namespace std::tr1;
vector<T> cont;
// ...
for_each( cont.begin(), cont.end(),
bind( &T::foo, 42 ) );
// assume void T::foo(int); exists
If you don't have tr1
you can use:
for_each( cont.begin(), cont.end(),
bind2nd( mem_fun( &s::foo ), 42 ) // first parameter is the object itself
);
I am not sure what you are trying to achieve here though. You have both compile time polymorphism (aka templates) and runtime polymorphism (aka virtual
member functions). The design seems a bit too complicated. In fact the following definition suffices:
int Execute()
{
int count = 0;
for( int i=0; i< MyArraySize; ++i ){
MyArray[ i ]->Foo(); // assume virtual int A::Foo(); exists
++count;
}
return count;
}
However, as you may have found out, virtual
members need to have the same signature in order to be overriden in sub-classes (otherwise you are overloading the function).
Note that the sample GetItems
does not call a member function of the contained objects, it calls a member, namely, push_back
on the vector
container object.
If all you want to do is to copy the pointers from a vanilla array to a vector
you could use vector
's specialized ctor that takes two iterators:
template<class T>
vector<T*> GetItems() // <-- This is the problem function
{
return vector<T*>( &MyArray[ 0 ], &MyArray[ 0 ] + MyArraySize );
}
精彩评论