2012-03-05 86 views
1

我需要計算指針數組的對象與賦予成員函數的參數具有相同名稱(成員變量)的次數。我嘗試過不同的方法,但都沒有工作。我的代碼甚至沒有編譯。錯誤是:「錯誤C2514:'MyComparator':類沒有構造函數」,這裏是我用於比較和用於計算協議的函數的類的代碼。在對象指針向量中使用STL算法(C++)

//definition of the vector 
vector<Class1*> files; 
... 
int Class2::countNames(string name) 
    { 
     return count_if(files.begin(), files.end(), bind2nd(MyComparator(),name)); 
    } 
... 
class MyComparator{ 
public: 
bool operator()(const CFileType*& ob1, const string &str) 
{ 
    return ob1->getName()==str; 
} 
}; 

我很困難這個好幾個小時,我想用STL來做。這裏的問題是我有一個指針向量,如果我有一個正常的向量它不需要謂詞函數,在我的情況下,我必須給它一個參數,我認爲bind2nd()是正確的方法。任何幫助將不勝感激!

回答

1

在C++ 11下,您可以使用lambda表達式,這比舊式的bind2nd容易得多。例如:

#include <string> 
#include <vector> 
#include <algorithm> 
#include <iostream> 

class Class1 { 
public: 
    Class1(const std::string& name) : Name(name) { 
    } 
    const std::string& getName() const { 
     return Name; 
    } 
private: 
    std::string Name; 
}; 

size_t CountMatchingNames(const std::vector<Class1*>& v, const std::string& name) { 
    return std::count_if(
     v.begin(), 
     v.end(), 
     [&name](Class1* c1) { return name == c1->getName(); } 
    ); 
} 

int main() { 

    Class1 rob("rob"); 
    Class1 bob("bob"); 
    Class1 mitch("mitch"); 

    std::vector<Class1*> v; 
    v.push_back(&bob); 
    v.push_back(&mitch); 
    v.push_back(&rob); 
    v.push_back(&mitch); 
    v.push_back(&bob); 
    v.push_back(&bob); 

    std::cout << "rob count:\t" << CountMatchingNames(v, "rob") << std::endl; 
    std::cout << "bob count:\t" << CountMatchingNames(v, "bob") << std::endl; 
    std::cout << "mitch count:\t" << CountMatchingNames(v, "mitch") << std::endl; 

    return EXIT_SUCCESS; 

} 

此打印:

rob count:  1 
bob count:  3 
mitch count: 2 
+0

非常感謝,它工作完美,它比使用** bold ** bind2nd()**更加緊湊** bold ** – Goshutu 2012-03-06 10:35:04

+0

@Goshutu我忘記了通過引用傳遞向量(請參閱編輯) 。這不會影響正確性,但會影響性能,因爲每次調用「CountMatchingNames」時不再需要複製向量。 – 2012-03-06 10:59:40

+0

沒有問題,因爲這是一個類的成員函數 – Goshutu 2012-03-06 17:46:14

1

首先,你需要確保,當你使用它的比較級是可以確定的:在前面定義的移動MyComparator定義countNames()將是我的第一步。也就是說,bind2nd()想知道它所處理的函數對象比你提供的要好一些:它通常想知道result_typefirst_argument_typesecond_argument_type。你可以從std::binary_function<bool, CFileType const*, std::string const&>或明確定義它們。雖然我不認爲這是必需的,但您可能需要使函數調用運算符const。另一方面,如果你正在定義一個函數對象而不是一個函數(你可以使用std::ptr_fun()來獲得必要的typedef;個人而言,我認爲這個名字的意思是讓這些人有吸引力,因爲它肯定不是很多有趣當你不得不使用它們),你可以去整個的方式,而不是用在首位粘合劑爭戰

class MyComparator { 
public: 
    MyComparator(std::string const& value): value_(value) {} 
    bool operator()(CFileType const* obj) const { 
     return obj->getName() == this->value_; 
    } 
private: 
    std::string value_; 
}; 
... 
std::count_if(files.begin(), files.end(), MyComparator(name)); 

您可以定義一個函數,並結合其在使用粘合劑得到大致相同的效果。 Typeically,我做錯了,當我不嘗試一下代碼,但它會是這個樣子:

bool myComparator(CFileType const* obj, std::string name) { 
    return obj->getName() == name; 
} 
... 
std::count_if(files.begin(), files.end(), 
       std::bind2nd(std::ptr_fun(myComparator), name)); 

如果你覺得你想通過引用傳遞的參數name而不是複製這一切的時候,您將無法使用std::bind2nd(),至少除非您使用C++ 2011編譯器:否則它將創建一個類型,該類型必須連續編譯器不會喜歡的const關鍵字。您可以使用例如boost::bind()不存在這個問題:

std::count_if(files.begin(), files.end(), boost::bind(myComparator, _1, name)); 

...並改變name參數的聲明是std::string const& name

1

您在這裏有幾個問題:

  • 它看起來像你使用它後確定MyComparator。類型需要在使用前定義。
  • 矢量包含Class1*,但比較器適用於CFileType*
  • 過時的bind1stbind2nd使用起來有點棘手,並且要求函數類型定義各種類型。假設你不能使用新的std::bind(或boost::bind),最簡單的方法來解決這個問題是MyComparatorstd::binary_function<Class1*, string, bool>
  • operator()需要聲明const繼承。

如果你的編譯器支持C++ 11,那麼你可以寫這更簡單地使用或者std::bind或λ:

count_if(files.begin(), files.end(), bind(MyComparator(), placeholders::_1, name)); 

count_if(files.begin(), files.end(), [&name](Class1 const * p){return p->getName()==name;}); 
1

原則的思想工作,但是:

  1. 比較器類必須在使用之前進行定義;
  2. 它必須繼承binary_function以包含必要的typedef;
  3. operator()需要聲明const

通過這些修正,下面的例子爲我工作:

#include <vector> 
#include <functional> 
#include <string> 
#include <algorithm> 
#include <iostream> 

using namespace std; 

struct Class1 { 
    string getName() const { return "aaa"; } 
}; 

//... 
class MyComparator: public binary_function<const Class1*, string, bool> { 
public: 
bool operator()(const Class1* ob1, const string &str) const 
{ 
    return ob1->getName()==str; 
} 
}; 

vector<Class1*> files; 
//... 
int countNames(string name) 
    { 
     return count_if(files.begin(), files.end(), bind2nd(MyComparator(),name)); 
    } 

int main() { 
    files.push_back(new Class1); 
    files.push_back(new Class1); 
    cout << countNames("aaa") << ' ' << countNames("bbb") << endl; 
} 

但是請注意,具有指針的矢量容易導致內存泄漏(如在我的例子)。考慮使用Boost.PointerContainer或(使用C++ 11)unique_ptr的容器。

+0

我已經試過這種方法,它沒有工作,出來了相同的錯誤消息,雖然,「Branko Dimitrijevic」的答案工作,我的程序運行現在好! – Goshutu 2012-03-06 10:32:26