使用STL / Boost / Lambdas调整Map迭代器

时间:2010-04-26 21:09:53

标签: c++ stl c++11 boost-bind

考虑以下非工作代码:

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. 标准STL功能对象&amp;使用bind + less<>但无需编写自定义仿函数的技术
  2. Boost.Bind
  3. C ++ 0x Lambdas
  4. 我知道我不是erase元素。别担心;我只是简化要解决的问题。

3 个答案:

答案 0 :(得分:3)

我不确定如何仅使用STL绑定器来执行此操作,但我认为您的主要问题是,您传递给remove的仿函数的内容不仅仅是int,而是pair<int, unsigned>

使用boost :: bind你会这样做:

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

使用lambda函数,它是这样的:

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

我没有检查过这个编译,抱歉。

答案 1 :(得分:2)

remove_if不适用于关联容器。但remove_copy_if可能会有效,但会以复制地图为代价。相反,我会使用count_if

1)标准STL功能对象&amp;使用bind + less&lt;&gt;的技术但无需编写自定义函子

// 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 Lambdas

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

答案 2 :(得分:1)

虽然由于上述原因我无法使remove_if算法工作,但我得到了count_if算法来处理一些精心设计的函子定义和组合。这些未在标准中定义,但它们受到SGI STL中可用内容的启发。

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