2010-08-19 194 views
1

我試圖使用std::vector<T*>::push_backstd::mem_funstd::binder1st,但它似乎不可行,可以這樣做嗎?使用std :: vector <T*> :: push_back與std :: mem_fun和std :: bind1st

我試着用下面的代碼來舉例說明。

#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

回答

1

的問題是,binder1st定義了operator( )爲:

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

和mem_fun1_t定義操作符()爲:

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 ::代替綁定:

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

還要注意的是,你有一個bug,並需要通過綁定&漚,而不是僅僅RET(如mem_fun預計一指針,mem_fun_ref可以工作)。

+1

該錯誤是一個錯字創建的例子,但謝謝! Boost現在不是真正的選擇。 =/ – Vargas 2010-08-19 19:38:57

+1

您始終可以滾動您自己的bind1st函數和binder1st結構。只需複製它們的實現,但將const T&t更改爲T t。這樣你就不會以雙引用結束。 – 2010-08-20 13:34:07

+0

謝謝,好主意! – Vargas 2010-08-20 19:16:21

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未調用所包含對象的成員函數,它調用vector容器對象上的成員,即push_back

如果你想要做的是指針從香草陣列複製到vector你可以使用vector的特殊構造函數帶有兩個迭代器:

template<class T> 
vector<T*> GetItems() // <-- This is the problem function 
{ 
    return vector<T*>(&MyArray[ 0 ], &MyArray[ 0 ] + MyArraySize); 
} 
+0

我實際上使用VS2005不支持std :: tr1,我編輯了問題來更新我的目標。我知道我可以將陣列複製到矢量中,我真的很想知道我究竟做了什麼錯誤... – Vargas 2010-08-19 18:54:07

+0

VS2005對TR1有有限的支持。但是IIRC'tr1 :: bind'不可用。然而,如果你試圖調用'A'或其子類的成員函數,'for_each'應該在沒有什麼變化的情況下工作。看到我更新的答案。 – dirkgently 2010-08-19 19:02:25

相關問題