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

How does bind know when to cast to pointer?

我在 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 以某种方式知道(在绑定时)指向成员函数的指针的第一个参数应该是一个指针。但在下面的示例中,它不知道这一点,并且由于从 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()

您看到的错误与 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 ,你甚至不需要在表达式中使用 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(); })

mem_fun的原因是:

Creates a member function wrapper object, deducing the target type from the template arguments. The wrapper object expects a pointer to an object of type T as the first parameter to its operator().

要完成同样的事情,您需要使用 std::mem_fun_ref(不需要 bind):

find_if(l.begin(), l.end(), std::mem_fun_ref(&Person::check))

但实际上,您应该更喜欢更通用的 std::mem_fn,它允许两者兼顾,另外前两者将在 C++17 中弃用:

Function template std::mem_fn generates wrapper objects for pointers to members, which can store, copy, and invoke a pointer to member. Both references and pointers (including smart pointers) to an object can be used when invoking a std::mem_fn.

std::bind 同样允许引用或指针:

As described in Callable, when invoking a pointer to non-static member function or pointer to non-static data member, the first argument has to be a reference or pointer (including, possibly, smart pointer such as std::shared_ptr and std::unique_ptr) to an object whose member will be accessed.