0

我想传递一个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<1>, std::_Mem_fn)>]':
prog.cpp:20:102: 这里需要
/usr/include/c++/6/bits/stl_numeric.h: 154:22:错误:不匹配调用 '(std::_Bind(std::_Placeholder<1>, std::_Mem_fn)>) (int&, foo* const&)'</p>

4

2 回答 2

2

好吧,很明显,第二个例子没有提到placeholders::_2. 当accumulate使用两个参数调用仿函数时,第二个参数将被忽略,并且您的代码试图将一个int和一个返回的内部类的实例相加mem_fn

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

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

更清楚这里发生了什么。

于 2017-07-26T15:29:39.837 回答
0

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

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

结果应该是size(foos) * 13, 因为plus13在每次迭代中用作它的加数。

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

不会编译,因为它试图将 的结果mem_fn(&foo::r)作为加数传递给plus. 由于那不能转换为int plus不能接受。但即使它可以转换为int,那也不是你要找的,你想接受第二个参数并调用foo::r它,将结果传递给plus. 因此我们知道我们需要看到,placeholders::_2在语句的某处使用,传递第二个参数来调用它的r方法。


我们需要绑定placeholders::_2以绑定到一个仿函数,该仿函数将调用r其参数上的方法。绑定当然需要bind,但实际上bind可以将方法作为一个参数

也就是说,bind(&foo::r, placeholders::_2)您的工作代码中的语句在非嵌套形式中没有任何意义;那个仿函数甚至不带 2 个参数!实际上有处理bind嵌套在 anotherbind中的特殊规则,以便它们可以共享 outerbind的占位符,以免无法将绑定参数传递给嵌套表达式:

如果存储的参数 arg 的类型T为 which std::is_bind_expression<T>::value == true(例如,另一个bind表达式直接传递到对 的初始调用bind),则bind执行函数组合:不是传递绑定子表达式将返回的函数对象,而是急切地调用子表达式,并将其返回值传递给外部可调用对象。如果bind子表达式有任何占位符参数,它们将与外部共享bind


在这个表达式中使用的唯一方法mem_fn是将它的结果bind传递给placeholders::_2:bind(mem_fn(&foo::r), placeholders::_2)这有效,但当简单bind(&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(); } )
于 2017-07-27T15:36:40.637 回答