bind如何知道何时转换为指针?

时间:2015-05-31 18:49:18

标签: c++ stl iterator

我在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()

2 个答案:

答案 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_ptrstd::unique_ptr之类的指针指向将访问其成员的对象。