【问题标题】:iterating over a std::map using boost::bind使用 boost::bind 迭代 std::map
【发布时间】:2012-02-26 13:15:42
【问题描述】:

我做了一个小例子来了解boost::bind () 是如何处理集合的。我有一个名为 Data 的类:

class Data
{
public:
    void print ();
    const std::string& get () const;
    std::string& get () ;
};

我创建了一个名为 samples 的数据对象 std::vector,并且我能够以与 std::mem_fun_ref 相同的方式使用 bind

std::for_each (samples.begin (),samples.end (),std::mem_fun_ref (&Data::print));
std::for_each (samples.begin (),samples.end (),boost::bind (&Data::print,_1));

基本思想是bind返回一个bind_t<RetType=void, ObjType=Data, ArgType=void>类型的函数对象。成员函数作为第一个参数允许编译器推导出RetTypeObjTypeArgType。占位符_1对应算法必须提供的数据对象。

然后std::for_each按以下方式调用函数对象“for each”元素:

for ( ; first!=last; ++first ) f(*first);

bind_t::operator(ObjType& obj) 被调用,它的定义应该是这样的:

return (obj.*_method ());

我创建了一个名为 Filter 的类,它对数据元素执行一些处理。

class Filter
{
    void filter (Data& data);
    ...
};

如果我想对向量中的数据元素应用过滤器,我会通过以下方式调用bind

std::for_each (samples.begin (),samples.end (),boost::bind (&Filter::filter,filter,_1));

for_eachData 对象传递给bind_t::operator()。在这种情况下,函数对象已经有了对象并且只需要参数,所以在这种情况下占位符 _1 指的是参数。

我的问题来了:

如果我必须遍历 std::map 而不是向量,如何使用 bind

(抱歉所有的解释,我只是想确保我了解bind 的工作方式)

【问题讨论】:

  • 总结一下,我的问题是std::for_each 将传递给我std::pair<key,Data>,而Filter::filter 期望引用Data
  • 你为什么不直接来这个问题? :) 为什么你认为它与迭代向量有什么不同?
  • 嗨 ArunMu,抱歉整个解释。我只是想确保我了解bind 的工作原理(也许我误解了一些东西)。与您的第二个问题相关,它会有所不同,因为现在函数对象接收 std::pair 而不是对下一个 vector 元素的引用。
  • 还是不清楚:(。你的地图看起来像地图,?>.
  • 地图看起来像:std::map<int,Data>,我想对所有数据元素应用过滤器。也就是说,如果我调用:std::for_each (sampleMap.begin (),sampleMap.end (),boost::bind (&Filter::filter,filter,_1)),我会收到以下错误:error: no match for call to (boost::_mfi::mf1<void, Filter, Data&>) (Filter&, std::pair<const int, Data>&)。现在for_each正在传递std::pair,因为我正在迭代地图而不是矢量。

标签: c++ boost stl map bind


【解决方案1】:
#include <boost/bind.hpp>
#include <algorithm>
int main()
{
  struct Sample
  {
    int i_;
    double d_;
  };
  typedef std::map<int, Sample> Samples;
  struct Filter
  {
    void filter(const Sample &s)
    {
    }
  };
  Filter filter;
  Samples samples;
  std::for_each(samples.begin(), samples.end(), boost::bind(&Filter::filter, filter, boost::bind(&Samples::value_type::second, _1))); 
}

【讨论】:

  • 你好。是否有可能获得双 d_;来自 &Samples::value_type::second ?
  • 我的意思不是通过第二个,而是通过第二个字段
  • @Max 你想遍历结构字段吗?好吧,这与原始问题无关,但只要我们在 c++ 中没有反射,就需要为此使用 boost::fusion 结构适配器。调整结构使其成为可迭代的融合序列。 (你最好打开另一个问题。)
  • 我用 lambda 解决了问题)我将阅读有关 fusion 的内容并提出新问题。谢谢
【解决方案2】:

当然,您可以使用bind() 来迭代std::map&lt;...&gt;。但是,请注意std::map&lt;K, V&gt; 中的元素具有std::pair&lt;K const, V&gt; 类型,即绑定函数需要是访问此类型对象的电缆。也就是说,我不知道单独使用bind() 可以将此参数转换为您真正感兴趣的参数(即V)。为此,您可能需要调用一个辅助函数来进行转换。如果你bind() 这个函数以及bind() 可以做一个合适的组合,即我认为这样的事情应该可以工作:

template <typename Result>
struct project2nd {
    typedef Result const& result_type;
    template <typename T>
    result_type operator()(std::pair<T, Result> const& arg) const {
        return arg.second;
    }
};
...
... bind(&Filter::filter, filter, bind(project2nd<Data>(), _1)) ...

对于bind() 与函数对象一起工作,它似乎需要一些有关相关类型的信息:函数调用运算符的结果无法推断,但显然在内部需要。我认为bind() 足够聪明,可以通过引用。否则需要将类型更改为Result。另外,我不知道bind() 是否也需要了解参数类型。如果是这样,project2nd 类 tmeplate 需要将这两种类型都作为参数。

【讨论】:

  • 您好 Dietmar,首先感谢您的回复。我已经尝试了您的解决方案,但出现了一些编译错误:/home/anibal/local/include/boost/bind/bind.hpp:69:37: error: no type named ‘result_type’ in ‘struct project2nd’ ... error: no match for call to ‘(boost::_mfi::mf1&lt;void, Filter, Data&amp;&gt;) (Filter&amp;, std::pair&lt;const int, Data&gt;&amp;)’ ... error: creating array with negative size (‘-0x00000000000000001’)
  • 呃,是的......我没有机会测试答案(我仍然没有它,就此而言)所以我忘记了使用@987654338的一些需求@ 带有函数对象。这个特殊的有点烦人,因为它要求在函数对象中定义result_type。反过来,这意味着它不能从函数调用运算符的参数中推导出来。我会用一种可能的方法来更新答案。副手,不知道有没有额外的要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
相关资源
最近更新 更多