【问题标题】:Why Can't I use a mem_fn Functor in bind?为什么我不能在绑定中使用 mem_fn Functor?
【发布时间】:2017-07-26 15:18:47
【问题描述】:

我想将mem_fn 参数传递给bind,但编译器似乎不允许这样做。

例如,这可以正常工作:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)));

但是当我尝试使用 mem_fn 仿函数时,我得到了一个错误页面:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r)));

/usr/include/c++/6/bits/stl_numeric.h: 在'_Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation) 的实例化中 [with _InputIterator = __gnu_cxx::__normal_iterator >; _Tp = int; _BinaryOperation = std::_Bind(std::_Placeholder, std::_Mem_fn)>]’:
prog.cpp:20:102: 从这里需要
/usr/include/c++/6/bits/stl_numeric.h:154:22:错误:不匹配调用 '(std::_Bind(std::_Placeholder, std::_Mem_fn)>) (int& , foo* const&)'

【问题讨论】:

  • 你是我看到的第一个在不知情的情况下使用bind 对嵌套绑定表达式的特殊处理的人。
  • mem_fn 已弃用,请勿使用。
  • @n.m.它是?我知道它里面的 typedefs 将在 C++17 中,但我没有看到任何关于 mem_fn 本身被弃用的信息。
  • @NathanOliver 抱歉把它和 mem_fun 搞混了。
  • @n.m.啊。是的,他们没有让这最容易保持直线。

标签: c++ c++11 bind functor mem-fun


【解决方案1】:

嗯,很明显,第二个例子没有提到placeholders::_2。当accumulate 使用两个参数调用函子时,第二个参数将被忽略,您的代码会尝试将intmem_fn 返回的内部类的实例相加。

我建议你放弃所有这些bind 游戏,并使用 lambda:

accumulate(cbegin(foos), cend(foos), 0, 
    [](int val, foo* f) { return val + f->r(); });

这里发生了什么更清楚了。

【讨论】:

    【解决方案2】:

    要理解这一点,请考虑一下如果您只是将文字传递给 bind 的 3rd 参数意味着什么。例如,如果你做了:

    accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, 13))
    

    结果应该是size(foos) * 13,因为plus 会使用13 作为每次迭代的加数。

    accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r)))
    

    无法编译,因为它试图将mem_fn(&amp;foo::r) 的结果作为plus 的加数传递。由于无法将其转换为 int plus 无法接受。但是,即使它可以转换为int,这也不是您要寻找的,您希望使用 2nd 参数并在其上调用foo::r,将结果传递给@ 987654336@。因此我们知道我们需要看到,placeholders::_2 在语句中的某处使用,传达了调用它的r 方法的第二个nd 参数。


    我们需要绑定 placeholders::_2 以绑定到一个仿函数,该仿函数将在其参数上调用 r 方法。绑定当然需要bind,但实际上需要bind can take a method as it's 1st argument

    也就是说,您的工作代码中的bind(&amp;foo::r, placeholders::_2) 语句在非嵌套形式中没有任何意义;那个仿函数甚至不带 2 个参数! 实际上有special rules for handling a bind nested within another bind,这样它们就可以共享外部bind 的占位符,以免无法将绑定参数传递给嵌套表达式:

    如果存储的参数 arg 是 std::is_bind_expression&lt;T&gt;::value == true 类型的 T(例如,另一个 bind 表达式直接传递到对 bind 的初始调用中),则 bind 执行函数组合:在传递绑定子表达式将返回的函数对象的过程中,立即调用子表达式,并将其返回值传递给外部可调用对象。如果bind 子表达式有任何占位符参数,它们将与外部bind 共享。


    在此表达式中使用mem_fn 的唯一方法是将其结果传递给bind 以传递placeholders::_2bind(mem_fn(&amp;foo::r), placeholders::_2) 这可行,但是当简单的bind(&amp;foo::r, placeholders::_2)就足够了。因此,生成此函子的最佳方法是使用您提供的语句:

    accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)))
    

    或者使用 lambda:

    accumulate(cbegin(foos), cend(foos), 0, [](const int augend, const auto& addend) { return augend + addend.r(); } )
    

    【讨论】:

      猜你喜欢
      • 2016-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-25
      • 2018-08-24
      • 1970-01-01
      相关资源
      最近更新 更多