4

次の動作しないコードを検討してください。

typedef map<int, unsigned> mymap;
mymap m;
for( int i = 1; i < 5; ++i )
    m[i] = i;
// 'remove' all elements from map where .second < 3
remove_if(m.begin(), m.end(), bind2nd(less<int>(), 3));

このマップから要素を削除しようとしてい.second < 3ます。これは明らかに正しく書かれていません。次を使用してこれを正しく記述するにはどうすればよいですか。

  1. bind+を使用する標準 STL 関数オブジェクトとテクニックですless<>が、カスタム ファンクターを記述する必要はありません。
  2. Boost.Bind
  3. C++0x ラムダ

eraseは要素をingしていないことを知っています。心配しないでください。解決する問題を単純化しているだけです。

4

3 に答える 3

3

STLバインダーだけを使用してこれを行う方法はわかりませんが、主な問題は、あなたが与えるファンクターに渡されているものがremove単なるではintなくpair<int, unsigned>.

boost::bind を使用すると、次のようになります。

remove_if(m.begin(), m.end(), bind(&std::pair<int, unsigned>::second, _1) < 3);

ラムダ関数を使用すると、次のようになります。

remove_if(m.begin(), m.end(), [](const std::pair<int, unsigned>& p) { return p.second < 3; } );

これがコンパイルされることを確認していません。申し訳ありません。

于 2010-04-26T21:40:29.950 に答える
2

remove_if連想コンテナでは機能しません。しかし、remove_copy_ifうまくいくかもしれませんが、マップをコピーすることを犠牲にして。代わりに、でそれを行いcount_ifます。

1)bind + less <>を使用するが、カスタムファンクターを作成する必要のない標準のSTL関数オブジェクトと手法

// I don't think it can be done with standard c++ without introducing new functors and adaptors.
std::size_t count = std::count_if( m.begin(), m.end(),
      std::sgi::compose1(
         std::bind_2nd( std::less<int>(), 3 ),
         &boost::get<1,mymap::value_type> ) );

2)Boost.Bind

std::size_t count = std::count_if( m.begin(), m.end(),
      boost::compose_f_gx(
         &boost::bind( std::less<int>, _1, 3 )
         &boost::get<1,mymap::value_type> ) );

3)C++0xラムダ

std::size_t count = std::count_if( m.begin(), m.end(),
      []( const mymap::value_type& item )
         { return item.second < 3; } );

remove_ifの動作が本当に必要な場合は、独自のアルゴリズムをロールする必要があります。連想コンテナで機能する変更標準アルゴリズムはないと思います。

template< typename FwdIter, typename AssocCont, typename Pred >
std::size_t assoc_remove_if( FwdIter iter, FwdIter end, AssocCont& cont, Pred pred )
{
   std::size_t count = 0;
   while( iter != end )
   {
      if( pred(*iter) )
      {
         ++count;
         iter = cont.erase(iter);
      }
      else
      {
         ++iter;
      }
   }
   return count;
}
于 2010-04-28T17:24:00.287 に答える
1

remove_if上記の理由でアルゴリズムを機能させることはできませんでしたが、アルゴリズムcount_ifはやや複雑なファンクターの定義と構成で機能するようになりました。これらは標準では定義されていませんが、SGISTLで利用可能なものから着想を得ています。

template <class Pair>
struct select2nd : std::unary_function<Pair, typename Pair::second_type>
{
  typedef std::unary_function<Pair, typename Pair::second_type> super;
  typedef typename super::result_type result_type;
  typedef typename super::argument_type argument_type;

  result_type & operator ()(argument_type & p) const {
    return p.second;
  }
  result_type const & operator ()(argument_type const & p) const {
    return p.second;
  }
};

template <class UnaryFunc1, class UnaryFunc2>
struct unary_compose : std::unary_function<typename UnaryFunc2::argument_type,
                                           typename UnaryFunc1::result_type>
{
  typedef std::unary_function<typename UnaryFunc2::argument_type,
                              typename UnaryFunc1::result_type> super;
  typedef typename super::result_type result_type;
  typedef typename super::argument_type argument_type;

  UnaryFunc1 func1_;
  UnaryFunc2 func2_;
  unary_compose(UnaryFunc1 f1, UnaryFunc2 f2) : func1_(f1), func2_(f2) {}
  result_type operator () (argument_type arg) {
    return func1_(func2_(arg));
  }
};

template <class UnaryFunc1, class UnaryFunc2>
unary_compose<UnaryFunc1, UnaryFunc2>
compose1(UnaryFunc1 f1, UnaryFunc2 f2) {
  return unary_compose<UnaryFunc1, UnaryFunc2>(f1,f2);
};

int main(void) {
  typedef std::map<int, unsigned> mymap;
  mymap m;
  for(int i = 0; i < 5; ++i )
    m[i] = i;

  std::cout << "Count = "
            << std::count_if(m.begin(), m.end(),
               compose1(std::bind2nd(std::less<int>(), 3), select2nd<mymap::value_type>()))
            << std::endl;
}
于 2010-04-28T03:41:08.200 に答える