我在C ++中发现了一件有趣的事情。
using namespace std;
struct Person {
string name;
bool check() {
return name == "carol";
}
};
int main()
{
Person p = { "Mark" };
list<Person> l;
l.push_back(p);
if (find_if(l.begin(), l.end(), bind(&Person::check, std::placeholders::_1)) == l.end())
{
cout << "Not found";
}
return 0;
}
上面的if语句可以正常工作。解除引用迭代器for_each获取和对象并将其传递给函数。不知何故bind知道(在biniding时)指向成员函数的第一个参数应该是一个指针。但是在下面的示例中,它并不知道并且由于从Person转换为Person *而引发错误。绑定如何工作呢?以及如何在以下示例中传递指针?
find_if(l.begin(), l.end(), bind(mem_fun(&Person::check), std::placeholders::_1)) == l.end()
我想出了类似的东西,但我不确定这是否是最佳方式。
find_if(l.begin(), l.end(), bind([](Person& p) { return p.check(); }, std::placeholders::_1)) == l.end()
答案 0 :(得分:4)
您看到的错误与bind
无关,它是mem_fun
's(已弃用,将在下一版本的C ++中删除)错误。当您使用mem_fun
将指针包装到成员函数时,您需要将指针传递给要调用成员函数的实例。
find_if
将取消引用迭代器并将结果传递给其谓词,这意味着您尝试将Person&
而不是Person*
传递给mem_fun_t
。如果要传递引用,请改用mem_fun_ref
。所以以下将编译
find_if(l.begin(), l.end(), bind(mem_fun_ref(&Person::check), std::placeholders::_1))
// ^^^^^^^^^^^
作为Barry points out,您在表达式中甚至不需要bind
,以下内容也适用
find_if(l.begin(), l.end(), mem_fun_ref(&Person::check))
或者使用mem_fun
/ mem_fun_ref
替换C ++ 11,mem_fn
find_if(l.begin(), l.end(), mem_fn(&Person::check))
最后,还可以使用lambda表达式
find_if(l.begin(), l.end(), [](Person& p) { return p.check(); })
答案 1 :(得分:3)
mem_fun
不的原因是:
创建成员函数包装器对象,从模板参数中推导出目标类型。包装器对象期望指向类型为
T
的对象的指针作为其operator()
的第一个参数。
要完成同样的事情,您需要使用std::mem_fun_ref
(不需要bind
):
find_if(l.begin(), l.end(), std::mem_fun_ref(&Person::check))
但实际上,您应该更喜欢允许两者的更通用std::mem_fn
,此外前两个将在C ++ 17中弃用:
函数模板std :: mem_fn为成员指针生成包装器对象,可以存储,复制和调用指向成员的指针。 调用
std::mem_fn
时,可以使用对象的引用和指针(包括智能指针)。
std::bind
同样允许引用或指针:
如Callable中所述,当调用指向非静态成员函数的指针或指向非静态数据成员的指针时,第一个参数必须是引用或指针(可能包括智能)诸如
std::shared_ptr
和std::unique_ptr
之类的指针指向将访问其成员的对象。