为什么 mem_fn() 抱怨尝试使用已删除的函数

why does mem_fn() complain about attempt to use a deleted function?

本文关键字:删除 函数 mem fn 为什么      更新时间:2023-10-16

我有以下代码片段:

struct Foo {
    Foo(int num):num_(num){}
    void print_add(int i) const { std::cout << num_+i << 'n'; }
    int num_;
};
int main() {
    std::vector<Foo*> vpf{ new Foo(3), new Foo(4), new Foo(5) };
    auto pfa =  std::mem_fn(&Foo::print_add);
    int i = 42;
    //std::for_each(vpf.begin(), vpf.end(), [&i](const auto& val){val -> print_add(i);});
    std::for_each(vpf.begin(), vpf.end(), pfa(&i));
    return 0;
}

使用 lambda 表达式的注释代码实际上按照我预期的打印 45、46、47 工作。使用mem_fn的带有std::for_each的未注释代码会导致编译错误attempt to use a deleted function

有人可以解释为什么以及如何在这种情况下正确使用mem_fn吗?

我不明白您如何从此代码中获得"尝试使用已删除的函数"错误。代码不准确,或者诊断消息不是列表中的第一个。

此代码中的第一个错误将引用您的 pfa(&i) 子表达式,该子表达式无效。首先,为了调用pfa您必须提供两个参数 - Foo *int类型 - 而您只提供int *类型中的一个。其次,在std::for_each的背景下,你根本不应该自己打电话pfa,你应该pfa本身传递给std::for_each

如果你想用"lambdaless"替换你的lambda,例如使用"classic"std::mem_fn函数对象,它看起来像这样

auto pfa = std::mem_fn(&Foo::print_add);
int i = 42;
std::for_each(vpf.begin(), vpf.end(), std::bind(pfa, std::placeholders::_1, i));

或者,使用现已弃用的 C++98 库功能

auto pfa = std::mem_fun(&Foo::print_add);
int i = 42;
std::for_each(vpf.begin(), vpf.end(), std::bind2nd(pfa, i));

(当时只是...不知何故更有趣。更有趣。盖迪特?哈...

附言请注意(如 @T.C. 在注释中指出的那样(,如果您打算在其上使用 std::bind,则无需通过 std::mem_fn 预先包装成员指针。第一个变体可以重写为

int i = 42;
std::for_each(vpf.begin(), vpf.end(), 
  std::bind(&Foo::print_add, std::placeholders::_1, i));

std::mem_fn创建一个函子,该函子将引用或指向类型的指针作为第一个参数,并将其其余参数转发给实际函数。

将其传递给算法时,您不应该调用它的()运算符(您没有为 lambda 示例执行此操作(。你的问题是你还想为你的函数提供一个参数,而这根本不可能只用mem_fn。不过,您可以使用std::bind或 lambda 来执行此操作。

std::for_each(vpf.begin(), vpf.end(), std::bind(pfa, std::placeholders::_1, i));

std::for_each(vpf.begin(), vpf.end(), [&i,&pfa](const auto& val){ pfa(val, i); });

话虽如此,我认为最好使用您示例中的 lambda。 bind是有争议的,如果你无论如何都在使用 lambda,那么添加mem_fn有什么意义呢?

auto pfa =  std::mem_fn(&Foo::print_add);

&Foo::print_add不是函数指针。它是一个类方法指针。不能将其作为函数指针调用。您必须为此方法提供类的实例,并通过指针调用实例的方法。

std::for_each(vpf.begin(), vpf.end(), pfa(&i));

您正在尝试调用pfa就好像它是一个函数指针一样,它不是。首先,对于每次调用,std::for_each按照迭代的顺序传递项目。这将是您需要与方法指针一起使用的类实例:

std::for_each(vpf.begin(), vpf.end(),
          [&i,&pfa](const auto& val){pfa(val, i);});

lambda 获取其参数(std::for_each迭代序列中的值(,并通过方法指针使用它来调用类方法。正如预期的那样,由此产生的输出是

45
46
47