0

マップに表示されるベクトルの要素を見つける必要があります。難しい部分は、ベクターが構造体で構成されているため、最初にメンバー関数を呼び出して構造体から値を抽出し、それをマップ要素と比較する必要があります。

したがって、 for cycle を使用すると、非常に簡単です。

vector<A>::iterator it;
for( it = vec.begin(); it != vec.end(); ++it )
{
    if( mp.count( it->getKey() ) )
    {
        break;
    }
}

私の質問: 1行でそれを行う方法はありますか?

//this doesn't work as count accepts key_type
vector<A>::iterator it = find_if( vec.begin(), vec.end(), boost::bind( &map<string, string>::count, mp, boost::bind( &A::getKey, _1 ) )) != 0);

テストする完全な例

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

#include <boost/bind.hpp>
#include <boost/assign.hpp>

using namespace std;

class A{
public:
    A( const std::string& key )
    : key( key ) {}

    std::string getKey(){ return key; }
private:
    std::string key;
};

int main(int argc, const char *argv[]) {

    map<string, string> mp = boost::assign::map_list_of( "Key1", "Val1" ) ( "Key2", "Val2" ) ( "Key3", "Val3" );
    vector<A> vec = boost::assign::list_of( "AAA" ) ( "Key2" ) ( "BBB" );

//    vector<A>::iterator it = find_if( vec.begin(), vec.end(), boost::bind( &map<string, string>::count, mp, boost::bind( &A::getKey, _1 ) )) != 0);
    vector<A>::iterator it;
    for( it = vec.begin(); it != vec.end(); ++it )
    {
        if( mp.count( it->getKey() ) )
        {
            break;
        }
    }

    cout << ( it != vec.end() ? "found" : "not found" ) << endl;

    return 0;
}

前もって感謝します

4

2 に答える 2

1

あなたの解決策は近かったです。閉じ括弧が1つだけ多すぎます。各レベルのインデントを使用して各括弧を改行に配置すると、無効な括弧が強調されます。

vector<A>::iterator it = find_if
(
  vec.begin(), vec.end(), boost::bind
  (
    &map<string, string>::count, &mp, boost::bind
    ( 
      &A::getKey, _1 
    )
  )
) // one too many
!= 0);

最も単純な形式では、行は次のようになりますiterator = find_if(...) != 0)。これにより、コンパイラは次のいずれかで失敗します。

  • 見つからないoperator!=(iterator, int)
  • )トークン!= 0)

正しいかっこで、!= 0によって提供される演算子のオーバーロードを使用しboost::bindます。行は次のようになります。

vector<A>::iterator it = find_if(vec.begin(), vec.end(),
  boost::bind(&map<string, string>::count, &mp,
              boost::bind(&A::getKey, _1)) != 0);

ただし、このような単純な操作の可読性を考慮してください。単純なforループが一般的でなく、十分に再利用できない場合は、便利な関数内に隠すことを検討してください。

template <typename InputIterator,
          typename C,
          typename Fn>
InputIterator find_if_contains(
  InputIterator first,
  InputIterator last,
  const C& container,
  Fn fn)
{
  while (first != last)
  {
    if (0 != container.count(fn(*first))) return first;
    ++first;
  }
  return last;
}

...

vector<A>::iterator it = find_if_contains(
   vec.begin(), vec.end(),
   mp, boost::bind(&A::getKey, _1)
);

それ以外の場合、カスタムの述語タイプは、さまざまなタイプで再利用するための追加の柔軟性を提供しながら、読みやすさを向上させる可能性があります。たとえば、さまざまなタイプの連想コンテナーで機能する次の述語タイプを考えてみましょう。

template <typename C,
          typename Fn>
struct contains_predicate
{
  contains_predicate(const C& container, Fn fn)
     : container_(&container), fn_(fn)
  {}

  template <typename T>
  bool operator()(T& t)
  {
    return 0 != container_->count(fn_(t));
  }

  const C* container_;
  Fn fn_;
};

template <typename C,
          typename Fn>
contains_predicate<C, Fn>
contains(const C& container, Fn fn)
{
  return contains_predicate<C, Fn>(container, fn);
}

...

vector<A>::iterator it = find_if(vec.begin(), vec.end(),
  contains(mp, boost::bind(&A::getKey, _1)));
于 2013-05-13T20:59:45.973 に答える
0

C++11 では、ラムダを使用します。

find_if(vec.begin(), vec.end(), [&](A const & a){return mp.count(a.getKey());});

しかし、均一な初期化ではなく Boost.Assign を使用しているため、おそらくそれはできません。bind残念ながら、そのようなファンクターを単独で作成する方法がわかりません。

于 2013-05-13T13:07:45.723 に答える