【问题标题】:Adapting Map Iterators Using STL/Boost/Lambdas使用 STL/Boost/Lambdas 适配 Map 迭代器
【发布时间】:2010-04-26 21:09:53
【问题描述】:

考虑以下非工作代码:

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 &lt; 3 的元素。这显然写得不正确。如何正确使用:

  1. 使用bind + less&lt;&gt; 的标准 STL 函数对象和技术,但无需编写自定义函子
  2. Boost.Bind
  3. C++0x Lambdas

我知道我不是eraseing 元素。不用担心;我只是简化要解决的问题。

【问题讨论】:

  • 我相信 #1 无法解决 - 成员函数只有绑定器,没有 "value iterators",我也不能来通过结合活页夹和&amp;std::map&lt;int,unsigned&gt;::value_type::second,可以使用合适的标准库函数。

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


【解决方案1】:

我不确定如何仅使用 STL 绑定器来执行此操作,但我认为您的主要问题是传递给您提供给 remove 的函子的不仅仅是 int 而是 pair&lt;int, unsigned&gt; .

使用 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; } );

抱歉,我还没有检查它是否可以编译。

【讨论】:

  • 我无法编译以上两个中的任何一个。似乎编译器不喜欢在 remove_if 算法期间完成的对的内部洗牌。 pair::first 是一个不能赋值的 const int。
  • 你说得对,我没有考虑容器类型。 remove_if 不适用于关联容器。我很确定我写的内容适用于矢量。
  • 使用 boost 绑定的好答案。我经常将! 运算符与绑定一起使用,但经常忘记其他运算符也是重载的。
【解决方案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 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;
}

【讨论】:

  • Boost.Compose 已被弃用并从 Boost 中删除 - 还是我在另一个模块中忽略了 compose_f_gxAFAIK 我们现在应该使用嵌套绑定:boost.org/doc/libs/1_42_0/libs/bind/bind_as_compose.cpp
  • 好电话,我从来没有在生产代码中使用过 compose 东西,所以我再也没有看过它。嵌套绑定更加优雅。
【解决方案3】:

虽然由于上述原因我无法让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;
}

【讨论】:

  • 好吧,问题是“无需编写自定义函子”。如果允许任何自定义函子,那么它是微不足道的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
相关资源
最近更新 更多