bind如何知道何时强制转换为指针

How does bind know when to cast to pointer?

本文关键字:转换 指针 何时强 何知道 bind      更新时间:2023-10-16

我在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*的强制转换而抛出错误。那么bind是如何工作的呢?如何在下面的例子中传递一个指针?

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的错误(已弃用,将在下一个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工作的原因是:

创建成员函数包装器对象,从模板参数推断目标类型。包装器对象需要一个指向类型为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等智能指针)。