1

とで使おうとしてstd::vector<T*>::push_backい ますが、実現可能ではないようですが、できますか?std::mem_funstd::binder1st

私は以下のコードで例示しようとしました。

#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;
}

私の目標は、選択したアイテム(「A」オブジェクトまたは「A」派生オブジェクト)をパラメーターとして受け取る関数を実行するように指示できるコンテナークラスを作成することです。しかし、私はそれをなんとか使用std::vector::push_packすることができませんでした。

4

2 に答える 2

1

問題は、binder1stがoperator()を次のように定義していることです。

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

mem_fun1_tはoperator()を次のように定義します。

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

問題は、push_backが次のように定義されていることです。

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

したがって、最終的には次のようになります。

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

と:

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

言い換えると、ポインタへの参照への参照。参照への参照はC++には存在しません。これを修正するために私が考えることができる唯一のまともな方法は、代わりにboost ::bindを使用することです:

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

また、バグがあり、retだけでなくbind&retを渡す必要があることにも注意してください(ただし、me​​m_funはポインターを予期しているため、mem_fun_refは機能します)。

于 2010-08-19T19:29:50.827 に答える
1

コンテナー内のアイテムのセット全体でメンバー関数を呼び出す最も簡単な方法は、次を使用すること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

持っていない場合は、tr1次を使用できます。

for_each( cont.begin(), cont.end(), 
   bind2nd( mem_fun( &s::foo ), 42 ) // first parameter is the object itself
);

ただし、ここで何を達成しようとしているのかわかりません。コンパイル時ポリモーフィズム (別名テンプレート) と実行時ポリモーフィズム (別名virtualメンバー関数) の両方があります。デザインは少し複雑すぎるようです。実際、次の定義で十分です。

int Execute()        
{
      int count = 0;
      for( int i=0; i< MyArraySize; ++i ){
          MyArray[ i ]->Foo(); // assume virtual int A::Foo(); exists
          ++count;
      }
      return count;
}

ただし、お気づきかもしれませんがvirtual、サブクラスでオーバーライドするには、メンバーに同じ署名が必要です (そうしないと、関数がオーバーロードされます)。

サンプルは、含まれているオブジェクトのメンバー関数を呼び出すのではなく、コンテナー オブジェクトのメンバーを呼び出すことに注意してGetItemsください。push_backvector

ポインタをバニラ配列から にコピーするだけの場合は、 2 つのイテレータを取る の特殊な ctor をvector使用できます。vector

template<class T>
vector<T*> GetItems()  // <-- This is the problem function
{
    return vector<T*>( &MyArray[ 0 ], &MyArray[ 0 ] + MyArraySize );
}
于 2010-08-19T18:39:10.730 に答える