简体   繁体   English

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

[英]C++ how to convert member functions to standalone functions (for use as function parameter) generically?

For function parameters of template functions I find myself often wrapping member functions inside a lambda to create identical standalone functions with the first parameter being the object. 对于模板函数的函数参数,我发现自己经常将成员函数包装在lambda中以创建相同的独立函数,第一个参数是对象。

A (dummy) example : 一个(虚拟)示例:

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;
}

Is there a way to define such lambdas more generically ? 有没有办法更一般地定义这样的lambdas? or is there a way to directly refer to the member functions instead of using lambdas ? 或者有没有办法直接引用成员函数而不是使用lambdas?

You can use C++14 generic lambdas to help with this. 您可以使用C ++ 14通用lambdas来帮助解决这个问题。 Define your generic lambda like this: 像这样定义你的通用lambda:

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

To digest: this creates a generic lambda, the invocation of which produces another lambda. 要消化:这会创建一个通用的lambda,其调用会产生另一个lambda。 The first lambda gets the member function you want to invoke, with any bound parameters (other than the this object). 第一拉姆达让你要调用的成员函数,与任何绑定参数(比其他this对象)。 It produces a second lambda, which just then expects the object itself and applies the member function call to it with the earlier-bound parameters. 它生成第二个lambda,然后它就会期望对象本身并使用先前绑定的参数对其应用成员函数调用。

So for your use case, you have the neat-looking: 因此,对于您的用例,您看起来很整洁:

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

The great thing about this is that exactly the same bindMem lambda will work for any class and any member function, with arbitrary argument lists. 关于这一点的bindMem是,完全相同的bindMem lambda将适用于任何类和任何成员函数,具有任意参数列表。 So it really is generic in the sense that you meant. 因此,你的意思是它真的是通用的。

You can use std::bind() for this. 你可以使用std::bind()

Bind takes a function and however many arguments you want to go with it and returns a nice std::function object. 绑定需要一个函数,无论你想要多少参数,都会返回一个很好的std::function对象。 You can specify the arguments at creation time or use placeholders to specify them when you're calling the returned 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);

Remember that non-static member functions take a class instance as their first argument (though most of the time it's done implicitly, this is not one of them), this is why we're using a placeholder. 请记住,非静态成员函数将类实例作为它们的第一个参数(尽管大多数情况下它是隐式完成的,但这不是其中之一),这就是我们使用占位符的原因。 When you do f(a) now, that a (the class instance) is substituted for that placeholder. 当你现在执行f(a)时, a (类实例)将替换该占位符。

Further reading: Bind , Placeholders 进一步阅读: 绑定占位符

After some researching, thanks to the suggestion of @happydave, I'll go with the following answer: 经过一番研究,感谢@happydave的建议,我将回答以下问题:

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

The second sum cannot be dealt with as such and should remain a lambda. 第二笔金额不能这样处理,应该保持为lambda。 However, in general, it appears to be the less likely case that the client code is the supplier of the arguments (in which case the arguments need to be passed anyhow to the template function (and a lambda capture is a great way)). 但是,一般来说,似乎客户端代码是参数的供应商的可能性较小(在这种情况下,参数需要以任何方式传递给模板函数(并且lambda捕获是一种很好的方式))。 In many cases, the template function supplies also the passed function's arguments and std::mem_fn would be fine. 在许多情况下,模板函数也提供传递函数的参数,std :: mem_fn也没问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM