C ++如何将成员函数转换为独立函数(用作函数参数)?

时间:2016-11-16 14:52:30

标签: c++ c++11 lambda wrapping member-functions

对于模板函数的函数参数,我发现自己经常将成员函数包装在lambda中,以创建相同的独立函数,第一个参数是对象。

一个(虚拟)示例:

class A
{
public:
    double f1() const;
    double f2(int i) const;

    // some data
};

template <typename Func>
double calculateSum(std::vector<A> as, Func f)
{
    double result = 0.0;
    for (auto a : as)
        result += f(a);
    return result;
}

int main()
{
    std::vector<A> as;
    int i = 0;
    auto sum1 = calculateSum(as, [](const A& a) { return a.f1(); });
    auto sum2 = calculateSum(as, [&i](const A& a) { return a.f2(i); });
    return 0;
}

有没有办法更一般地定义这样的lambdas?或者有没有办法直接引用成员函数而不是使用lambdas?

3 个答案:

答案 0 :(得分:4)

您可以使用C ++ 14通用lambdas来帮助解决这个问题。像这样定义你的通用lambda:

auto bindMem = [](auto f, auto& ... memArgs) { return [f, &memArgs...](auto& a) { return (a.*f)(memArgs...); }; };

要消化:这会创建一个通用的lambda,其调用会产生另一个lambda。第一个lambda使用任何绑定参数(this对象除外)获取要调用的成员函数。它会生成第二个lambda,然后它会期望对象本身并使用先前绑定的参数对其应用成员函数调用。

因此,对于您的用例,您看起来很整洁:

auto sum1 = calculateSum(as, bindMem(&A::f1));
auto sum2 = calculateSum(as, bindMem(&A::f2,i));

关于这一点的好处是完全相同的bindMem lambda将适用于任何类和任何成员函数,具有任意参数列表。从某种意义上讲,它确实是通用的。

答案 1 :(得分:2)

您可以使用std::bind()

Bind接受一个函数,无论你想要多少个参数,都会返回一个漂亮的std::function对象。您可以在创建时指定参数,也可以在调用返回的函数时使用占位符指定它们。

#include <functional>
...
auto sum1 = calculateSum(as, std::bind(&A::f1, std::placeholders::_1));
auto sum2 = calculateSum(as, std::bind(&A::f2, std::placeholders::_1, i);

请记住,非静态成员函数将类实例作为它们的第一个参数(尽管大多数情况下它是隐式完成的,但这不是其中之一),这就是我们使用占位符的原因。 现在执行f(a)时,a(类实例)将替换该占位符。

进一步阅读:BindPlaceholders

答案 2 :(得分:2)

经过一番研究,感谢@happydave的建议,我会回答以下问题:

auto sum1 = calculateSum(as, std::mem_fn(&A::f1));

第二笔金额不能如此处理,应保持为lambda。但是,一般来说,似乎客户端代码是参数的供应商的可能性较小(在这种情况下,参数需要以任何方式传递给模板函数(并且lambda捕获是一种很好的方式))。在许多情况下,模板函数也提供传递函数的参数,std :: mem_fn也没问题。