为什么我不能在绑定中使用mem_fn函子?
Why Can't I use a mem_fn Functor in bind?
我想将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( [其中 _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::_占位符<1>, std::_Mem_fn(>( (int&, foo* const&('
嗯,很明显,第二个例子没有提到placeholders::_2
。当accumulate
使用两个参数调用函子时,将忽略第二个参数,并且代码正在尝试将int
和mem_fn
返回的内部类的实例相加。
我建议你放弃所有这些bind
游戏,并使用lambda:
accumulate(cbegin(foos), cend(foos), 0,
[](int val, foo* f) { return val + f->r(); });
更清楚这里发生了什么。
要理解这一点,想想如果你只是把一个文字传递给bind
的第3个参数意味着什么。例如,如果您已完成:
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(&foo::r)
的结果作为plus
的补充传递。既然不能转换成int
plus
就不能接受。但即使它可以转换为int
,这不是你要找的,你想取第二个参数并调用它foo::r
,将结果传递给plus
。因此,我们知道我们需要看到,placeholders::_2
语句中的某处使用,传达调用其r
方法的第二个参数。
我们需要绑定placeholders::_2
绑定到一个函子,该函子将在其参数上调用r
方法。绑定当然需要bind
,但实际上bind
可以采用一个方法,因为它是第一个参数。
也就是说,工作代码中的bind(&foo::r, placeholders::_2)
语句在非嵌套形式下没有任何意义; 该函子甚至不需要 2 个参数! C++实际上有特殊的规则来处理嵌套在另一个bind
中的bind
,以便它们可以共享外部bind
的占位符,以免无法将绑定参数传达给嵌套表达式:
如果存储的参数 arg 属于
std::is_bind_expression<T>::value == true
的T
类型(例如,另一个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(); } )
- 在"template"和函数声明之间使用:template<typename trait> using tr = base_trait<trait> void fn(tr::t
- "double* grade"、"double *grade"和"double* fn()"有什么区别?
- 通过实用程序 fn 将捕获的 lambda 传递给 C 样式回调 - 错误
- v8 源代码中 ArrayMap 函数的回调 fn 参数是什么?
- (C++)如何在不导致 mem 泄漏的情况下将指针传递到分配了'new'的函数?
- 如何释放子阵列的mem,它是更大数组的一部分
- 为什么移动语义与动态 mem 分配中的浅拷贝具有相同的行为
- 标准库中是否有相当于 Rust 的 'std::mem::d rop' 的C++?
- 使用 new 而不是 malloc 分配 mem
- fn 指针的向量没有显示正确的大小()
- 为什么未初始化的指针会导致接近 0 的 mem 访问冲突
- .Net字符串是否可以在不复制的情况下交给fn(const char16_t*str)
- 新 X 在作为参数传递给函数时是否会导致 mem 泄漏
- 引用变量如何存储在mem中
- C++:将mem乐趣用于自己的结构
- 在CUDA中具有共享MEM的非方面矩阵转置
- 修改filter_iterator谓词以接受BOOST中的两个参数(二进制fn)
- 变分递归模板mem有趣的专业化
- 如何创建像"Fn"+Key_Up这样的QKeySequence
- 从 ZedBoard 上的 GNU Radio 访问 /dev/mem