1

ポインターの配列のオブジェクトが、メンバー関数に指定されたパラメーターと同じ名前 (メンバー変数) を持つ回数を数える必要があります。さまざまなアプローチを試しましたが、どれもうまくいきませんでした。私のコードはコンパイルさえしません。エラーは次のとおりです:「エラー C2514: 'MyComparator': クラスにコンストラクターがありません」。比較に使用するクラスのコードと、同時実行数のカウントに使用する関数を次に示します。

 //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() が正しい方法だと思います。どんな助けでも大歓迎です!

4

4 に答える 4

1

C++11 では、ラムダ式を使用できますが、これは古風な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
于 2012-03-06T00:08:24.303 に答える
1

まず、比較クラスを使用するときにそのクラスが認識されていることを確認する必要があります。 の定義のMyComparator前に の定義を移動するcountNames()ことが、私の最初のステップです。とは言っbind2nd()ても、 は、あなたが提供するものよりも、扱っている関数オブジェクトを知りたがっています。一般にresult_type、 、first_argument_type、およびを知りたがっていsecond_argument_typeます。これらは、から取得するstd::binary_function<bool, CFileType const*, std::string const&>か、明示的に定義することで取得できます。必須ではないと思いますが、関数呼び出しを operator にしたい場合がありますconst。一方、関数ではなく関数オブジェクトを定義している場合(必要なtypedefs を使用して取得できますstd::ptr_fun()。個人的には、名前は確かにそれほど多くないため、これらの人を何らかの形で魅力的にすることを意図していると思いますそれらを使用する必要がある場合は楽しい)、最初からバインダーに干渉する必要はありません。

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));

関数を定義してバインドする場合、バインダーを使用してほぼ同じ効果を得ることができます。典型的には、コードを試してみないと間違ってしまいますが、次のようになります。

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

于 2012-03-06T00:11:34.257 に答える
1

ここでいくつかの問題があります。

  • MyComparator使用後に定義しているようです。型は使用前に定義する必要があります。
  • ベクトルには が含まれていますClass1*が、コンパレータは で動作しCFileType*ます。
  • deprecatedbind1stbind2ndは少し使いにくく、関数型によってさまざまな型を定義する必要があります。std::bindnew (または)を使用できないと仮定するとboost::bind、それを修正する最も簡単な方法は、 forMyComparatorから継承することですstd::binary_function<Class1*, string, bool>
  • を宣言するoperator()必要がありますconst

std::bindコンパイラが C++11 をサポートしている場合は、またはラムダを使用して、これをより簡単に記述できます。

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;});
于 2012-03-06T00:14:17.440 に答える
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 では) s のコンテナーの使用を検討してくださいunique_ptr

于 2012-03-06T00:22:53.580 に答える