为什么要使用mem_fn?

时间:2016-05-16 17:14:38

标签: c++ c++11 stdbind

我很困惑为什么需要std::mem_fn

我有一个函数可以接受任何可调用的(lambda,函数指针等),并将它绑定到一个参数。

例如:

template<class T>
void Class::DoBinding(T callable) {
  m_callable = std::bind(callable, _1, 4);
}
//somewhere else
Item item;
m_callable(item);

我见过的所有代码示例都是:

//some defined member function
Item::Foo(int n);

DoBinding(std::mem_fn(&Item::Foo));

为什么不能简单地说:

DoBinding(&Item::Foo);

看来后者可以调用而不必使用std :: mem_fn,那为什么需要呢?

2 个答案:

答案 0 :(得分:14)

这是因为期望UnaryFunctionBinaryFunction的通用代码将使用常规调用语法直接调用它。因此,要选择像for_each这样的任意算法,它可以像:

一样实现
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
    for (; first != last; ++first) {
        f(*first); // <== N.B. f(*first)
    }
    return f;
}

如果您使用for_each()致电&Item::Foo,则代码会尝试调用(&Item::Foo)(x),因为指向您必须编写(x.*&Item::Foo)()的成员的指针格式不正确。它是mem_fn要解决的语法差异:mem_fn处理指向成员的指针的调用语法,以便您可以使用指向成员以及函数的所有算法。功能对象。您不能拥有for_each(v.begin(), v.end(), &Item::Foo),但可以拥有for_each(v.begin(), v.end(), mem_fn(&Item::Foo))

这在std::bind()(以及std::threadstd::function和...)中本身就可以正常工作,因为这些都是对指向成员的指针的明确处理。由于DoBinding()本身会调用std::bind(),因此在这种情况下{/ 1}} 没有理由

是一个摆脱这种语法差异的提议:P0312。它进展不顺利。

答案 1 :(得分:10)

通常这样做是因为撰写DoBinding(std::mem_fn(&Item::Foo))的人不知道DoBinding可以直接获取成员指针。

请记住:std::sort(..., &Item::Foo)失败,因为sort期望该值是可直接调用的函数对象。成员指针不是。实际上,当给定成员指针而不是直接可调用类型时,C ++标准库中的每个算法都会失败。您的DoBinding仅适用,因为您正在使用std::bind,它对成员指针有特殊的重载。 DoBinding的来电者并不一定知道你这样做。

大多数按模板参数获取callables的代码都会阻塞成员指针。所以为了安全起见,我们不会将成员指针作为可直接调用的对象传递;使用mem_fn将其变成这样的对象。