【问题标题】:Why use mem_fn?为什么要使用 mem_fn?
【发布时间】:2016-09-12 13:46:46
【问题描述】:

我很困惑为什么需要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即可调用,那么为什么需要它呢?

【问题讨论】:

  • 不,你不需要mem_fn。你确实需要它来做其他事情。
  • 您永远不应该将未知类型的值传递给std::bind。如果该类型本身是一个绑定表达式,那么该行为就会令人惊讶。换句话说,std::bind 应该用在叶代码中,而不是在通用代码中。
  • 使用 lambda 代替 std::bind 怎么样?我觉得语法更清晰,当你开始使用 C++14 时,它应该涵盖所有(几乎所有?)与 bind 相同的用例
  • @AndyG 除了“几乎所有”实际上并没有涵盖 OP 询问的情况。
  • @Barry:但它应该使用 C++14,不是吗?我意识到标签是 C++11,所以也许评论有点误导。

标签: c++ c++11 stdbind


【解决方案1】:

这是因为需要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;
}

如果您用&amp;Item::Foo 调用for_each(),代码会尝试调用(&amp;Item::Foo)(x),这是不正确的,因为对于指向成员的指针,您必须编写(x.*&amp;Item::Foo)()mem_fn 旨在解决的语法差异是:mem_fn 处理指向成员的指针的调用语法,因此您可以使用指向成员以及函数和函数对象的所有算法。你不能拥有for_each(v.begin(), v.end(), &amp;Item::Foo),但你可以拥有for_each(v.begin(), v.end(), mem_fn(&amp;Item::Foo))

这在std::bind()(和std::threadstd::function 和...)中工作得很好,因为它们都对指向成员的指针分别进行了显式处理。而且由于DoBinding() 本身调用std::bind(),所以std::mem_fn 没有理由在这种情况下


is 提出了消除这种句法差异的建议:P0312。它并不顺利。

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-18
    • 2011-03-06
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2017-05-16
    • 2012-08-22
    相关资源
    最近更新 更多