std::bind2nd的替代方案

16

我有一个名为foostd::vector<int>,它代表一组范围的“边界”值。

例如,如果foo是{1, 3, 5, 7, 11},则这些范围分别是1-3、3-5、5-7、7-11。对我来说,这等同于4个时间段。请注意,每个时间段包括范围内的第一个数字,而不是最后一个数字。因此,在我的例子中,8出现在第3(从零开始)个时间段中。7也出现在第3个时间段中。11及以上的数字没有出现在任何时间段中。2出现在第0个时间段中。

给定一个名为barint,我使用

std::find_if(
    foo.begin(),
    foo.end(),
    std::bind2nd(std::greater<int>(), bar)
) - foo().begin() - 1;

给我应该包含bar的周期。

我的问题是:std::bind2nd已被弃用,因此我应该重构。使用更新的函数,等价语句是什么?std::bind并不会以明显的方式“落入”其中。


3
顺便说一下,std::distance(foo.begin(), std::lower_bound(foo.begin(), foo.end(), bar)) - 1; 在这里似乎更合适。 - Jarod42
“c++11”标签是否是必需的,还是仅当问题被提出时很适合?无论如何,如果您现在真正接受较新版本,您可以进行“标记”,以允许@TemplateRex的答案完全匹配阻抗。(请参见评论。) - Sz.
3个回答

20

C++11中,你可以使用std::bind;只是如何使用它不是很明显:

#include <functional>
using namespace std::placeholders;
std::find_if(
    foo.begin(),
    foo.end(),
    // create a unary function object that invokes greater<int>::operator()
    // with the single parameter passed as the first argument and `bar` 
    // passed as the second argument
    std::bind(std::greater<int>(), _1, bar)
) - foo().begin() - 1;

关键在于使用占位符参数,这些参数声明在std::placeholders命名空间中。std::bind返回一个函数对象,当它被调用时会接受一些参数。在调用std::bind时使用的占位符展示了在调用绑定对象时提供的参数如何映射到您将要绑定的可调用对象的参数列表。因此,例如:

auto op1 = std::bind(std::greater<int>(), _1, bar);
op1(5); // equivalent to std::greater<int>()(5, bar)

auto op2 = std::bind(std::greater<int>(), bar, _1);
op2(5); // equivalent to std::greater<int>()(bar, 5)

auto op3 = std::bind(std::greater<int>(), _2, _1);
op3(5, bar); // equivalent to std::greater<int>()(bar, 5)

auto op4 = std::bind(std::greater<int>(), _1, _2);
op4(5, bar); // equivalent to std::greater<int>()(5, bar)

16

使用C++14的通用lambda表达式(bind2nd),直接跳过青铜时代(bind)进入铁器时代,这个想法如何?

std::find_if(foo.begin(), foo.end(), [&](auto const& elem) { 
    return elem > bar; 
}); 

如果输入已经被排序

std::lower_bound(foo.begin(), foo.end(), bar); 

Lambdas相对于std::bind表达式来说更易于阅读,也更容易内联。例如,请参见Lavevej's CppCon 2015演讲。


2
我同意这可能是最易读的解决方案,但问题的标签只包括C++11。 - Jason R
3
@JasonR 我的哲学是展示我如何编写代码,除非他们声称真的不能使用C++14,即使如此,如果节省足够大,我也会展示它 :) Q&A 不仅仅是为了 OP,而是为了广大公众。但我点赞了你的 bind 答案 :) - TemplateRex
很好,那很有道理。+1。 - Jason R
@JasonR 顺便说一下,Scott Meyers之前有一个叫做“burying bind”的演讲。 - TemplateRex

6

bind版本将是:

bind(std::greater<int>(), placeholders::_1, bar)

但我认为,更加鼓励使用lambda表达式,如下所示:

[bar](const int a){return bar < a;}

建议使用重载函数begin/end而非方法调用,例如:

find_if(begin(foo), end(foo), [bar](const int a){return bar < a;})

placeholders::_1是什么? - P45 Imminent
你能否成为一个天使,把整个东西组合起来呢?;-) - P45 Imminent
@P45Imminent 字面上的 _placeholders_;请参见这里 - behzad.nouri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接